链表基础操作(含菜单选择)
- 格式:pdf
- 大小:336.43 KB
- 文档页数:7
实验一线性表的基本操作实现及其应用一、实验目的1、熟练掌握线性表的基本操作在两种存储结构上的实现。
2、会用线性链表解决简单的实际问题。
二、实验内容题目一、该程序的功能是实现单链表的定义和操作。
该程序包括单链表结构类型以及对单链表操作的具体的函数定义和主函数。
其中,程序中的单链表(带头结点)结点为结构类型,结点值为整型。
单链表操作的选择以菜单形式出现,如下所示:please input the operation:1.初始化2.清空3.求链表长度4.检查链表是否为空5.检查链表是否为满6.遍历链表(设为输出元素)7.从链表中查找元素8.从链表中查找与给定元素值相同的元素在表中的位置9.向链表中插入元素 10. 从链表中删除元素其他键退出。
其中黑体部分必做题目二、约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码。
开始时任选一个正整数做为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他的下一个人开始重新从1报数。
如此下去,直到所有人全部出列为止。
令n最大值取30。
要求设计一个程序模拟此过程,求出出列编号序列。
struct node(一)1.进入选择界面后,先选择7,进行插入:2.选择4,进行遍历,结果为:3.选择2,得出当前链表长度.4.选择3,得出当前链表为.5.选择分别选择5、6进行测试.6.选择8,分别按位置和元素值删除.7.选择9,或非1-8的字符,程序结束.(二) 实验总结通过这次实验,我对线性链表有了更深的理解,深入明白了线性存储结构与链式存储结构在内存存储的不同特点,同时我还学会了用这些知识实际解决一些问题,能够更加熟练地将算法转化为实际程序。
同时,在写程序和调试程序的过程中,学会了一些书写技巧和调试技巧,这对于自己能在短时间高效的写出正确地程序有很大作用。
四、主要算法流程图及程序清单 1. 主要算法流程图:(1) 从单链表表中查找与给定元素值相同的元素在链表中的位置p=p->nextp&&!(p->data==xtrue调用函数,传入参数L ,xp=L->next2.程序清单:#include<iostream> using namespace std; #include<>#include<>/* 预处理命令 */#define OK 1;#define ERROR 0;#define OVERFLOW -1;/* 单链表的结点类型 */typedef struct LNode{int data;struct LNode *next;}LNode,*LinkedList;/*初始化单链表*/LinkedList LinkedListInit(){空"<<endl;cout<<"\t\t\t"<<"2.求链表长度"<<endl;cout<<"\t\t\t"<<"3.检查链表是否为空"<<endl;cout<<"\t\t\t"<<"4.遍历链表"<<endl;cout<<"\t\t\t"<<"5.从链表中查找元素 "<<endl;cout<<"\t\t\t"<<"6.从链表中查找与给定元素值相同的元素在表中的位置"<<endl;cout<<"\t\t\t"<<"7.向链表中插入元素"<<endl;cout<<"\t\t\t"<<"8.从链表中删除元素"<<endl;cout<<"\t\t\t"<<"9.退出"<<endl;}/*主函数*/int main(){链表长度case 2:{cout<<"\t\t\t链表长度为:"<<LinkedListLength(L)<<endl;getch();}break;查链表是否为空case 3:{if (!LinkedListEmpty(L)){cout<<"\t\t\t链表不为空!"<<endl;}else{cout<<"\t\t\t链表为空!"<<endl;}getch();}break;历链表case 4:{LinkedListTraverse(L);getch();}break;链表中查找元素case 5:{cout<<"\t\t\t请输入要查询的位置i:";int j;cin>>j;if (LinkedListGet(L,j)){cout<<"\t\t\t位置i的元素值为:"<<LinkedListGet(L,j)->data<<endl;}else{cout<<"\t\t\ti大于链表长度!"<<endl;}getch();}break;链表中查找与给定元素值相同的元素在表中的位置case 6:{cout<<"\t\t\t请输入要查找的元素值:";int b;cin>>b;if (LinkedListGet1(L,b)){cout<<"\t\t\t要查找的元素值位置为:"<<LinkedListGet1(L,b)<<endl;cout<<"\t\t\t要查找的元素值内存地址为:"<<LinkedListLocate(L,b)<<endl;}else{cout<<"\t\t\t该值不存在!"<<endl;}getch();}break;链表中插入元素case 7:{cout<<"\t\t\t请输入要插入的值:";int x; cin>>x;cout<<"\t\t\t请输入要插入的位置:";int k; cin>>k;if(LinkedListInsert(L,k,x)){cout<<"\t\t\t插入成功!"<<endl;}else{cout<<"\t\t\t插入失败!"<<endl;}getch();}break;链表中删除元素case 8:{cout<<"\t\t\t1.按位置删除"<<endl;cout<<"\t\t\t2.按元素删除"<<endl;int d;cout<<"\t\t请选择:";cin>>d;switch(d){case 1:{cout<<"\t\t\t请输入删除位置:";cin>>d;int y;if (LinkedListDel(L,d,y)){cout<<"\t\t\t"<<y<<"被删除!"<<endl;}else{cout<<"\t\t\t删除失败!"<<endl;}}break;case 2:{cout<<"\t\t\t请输入删除元素:";int y;cin>>y;if (LinkedListDel(L,y)){cout<<"\t\t\t"<<y<<"被删除!"<<endl;}else{cout<<"\t\t\t删除失败!"<<endl;}}}getch();}break;}}return 1;}题二约瑟夫环问题算法、思想为了解决这一问题,可以先定义一个长度为30(人数)的数组作为线性存储结构,并把该数组看成是一个首尾相接的环形结构,那么每次报m的人,就要在该数组的相应位置做一个删除标记,该单元以后就不再作为计数单元。
10)调用头插法的函数,分别输入10,20,分别回车:
11)调用尾插法的函数,分别输入30,40
12)查找单链表的第四个元素:
13)主函数中传入参数,删除单链表的第一个结点:
14)主函数传入参数,删除第0个未位置的元素,程序报错:
15)最后,输出单链表中的元素:
return 0;
}
6)编译,连接,运行源代码:
7)输入8,回车,并输入8个数,用空格分隔开,根据输出信息,可以看出,链表已经拆分为两个
五、实验总结
1.单链表采用的是数据+指针的表示形式,指针域总是指向下一个结
点(结构体)的地址,因此,在内存中的地址空间可以是不连续的,操作比顺序存储更加的方便
2.单链表使用时,需要用malloc函数申请地址空间,最后,删除元
素时,使用free函数释放空间。
数据结构-单链表基本操作实现(含全部代码)今天是单链表的实现,主要实现函数如下:InitList(LinkList &L) 参数:单链表L 功能:初始化时间复杂度 O(1)ListLength(LinkList L) 参数:单链表L 功能:获得单链表长度时间复杂度O(n)ListInsert(LinkList &L,int i,ElemType e) 参数:单链表L,位置i,元素e 功能:位置i后插时间复杂度O(n)[加⼊了查找]若已知指针p指向的后插 O(1)ListDelete(LinkList &L,int i) 参数:单链表L,位置i 功能:删除位置i元素时间复杂度O(n)[加⼊了查找]若已知p指针指向的删除最好是O(1),因为可以与后继结点交换数据域,然后删除后继结点。
最坏是O(n),即从头查找p之前的结点,然后删除p所指结点LocateElem(LinkList L,ElemType e) 参数:单链表L,元素e 功能:查找第⼀个等于e的元素,返回指针时间复杂度O(n)代码:/*Project: single linkeed list (数据结构单链表)Date: 2018/09/14Author: Frank YuInitList(LinkList &L) 参数:单链表L 功能:初始化时间复杂度 O(1)ListLength(LinkList L) 参数:单链表L 功能:获得单链表长度时间复杂度O(n)ListInsert(LinkList &L,int i,ElemType e) 参数:单链表L,位置i,元素e 功能:位置i后插时间复杂度O(n)[加⼊了查找]若已知指针p指向的后插 O(1)ListDelete(LinkList &L,int i) 参数:单链表L,位置i 功能:删除位置i元素时间复杂度O(n)[加⼊了查找]若已知p指针指向的删除最好是O(1),因为可以与后继结点交换数据域,然后删除后继结点。
c语言链表操作题C语言链表操作题一、问题描述假设有一个链表,每一个节点都包含一个整数,节点的结构体定义如下:```struct ListNode {int val;struct ListNode *next;};```请你完成以下链表操作函数:1. `struct ListNode* createList(int *arr, int size)`:传入一个整数数组和数组的长度,返回一个链表的头节点,链表的节点顺序和数组顺序一致。
2. `void displayList(struct ListNode *head)`:传入链表的头节点,打印链表中所有的节点值,用空格隔开,最后换行。
3. `int lengthOfList(struct ListNode *head)`:传入链表头节点,返回链表的长度。
4. `void insertNode(struct ListNode *head, int index, int val)`:传入链表的头节点、插入的位置和插入的值,在指定位置插入一个新节点。
5. `void deleteNode(struct ListNode *head, int index)`:传入链表的头节点和删除的位置,删除指定位置的节点。
6. `void reverseList(struct ListNode *head)`:传入链表的头节点,翻转整个链表。
7. `int findValInList(struct ListNode *head, int val)`:传入链表的头节点和要查找的值,返回第一个匹配的节点的下标,如果没有匹配的,则返回-1。
二、解题思路1. 创建链表:根据数组中元素的数量,循环遍历数组,每结构体当做链表节点,并记录对应下一个节点,最后返回链表头节点。
2. 打印链表:循环遍历链表的每一个节点,打印节点的val,并在每个节点之间添加空格,最后在尾部添加换行符。
3. 计算链表长度:从链表头节点开始循环遍历每一个节点,直到当前节点的next指针指向NULL,每遍历到一个节点就计数器加1。
二叉链表基本概念二叉链表是一种数据结构,它由节点组成,每个节点包含两个部分:数据和指向其子节点的指针。
二叉链表通常用于表示二叉树,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。
以下是关于二叉链表的详细介绍:一、基本概念1. 节点:节点是二叉链表中的基本单位,每个节点包含两部分:数据和指针。
数据用于存储实际信息,而指针则指向该节点的子节点。
每个节点都有两个指针,一个指向左子节点,另一个指向右子节点。
2. 左子节点和右子节点:在二叉链表中,每个节点最多有两个子节点:左子节点和右子节点。
左子节点的指针指向节点的左子树,右子节点的指针指向节点的右子树。
3. 父节点和孩子节点:在一个二叉链表中,如果一个节点B是另一个节点A的子节点,则A被称为B的父节点,B被称为A的孩子节点。
4. 空节点:在二叉链表中,如果一个节点的父节点为空,则该节点被称为根节点。
如果一个节点的孩子节点为空,则该节点被称为叶节点。
二、基本操作1. 插入操作:插入操作是向二叉链表中添加一个新的节点。
新节点的父节点可以根据需要选择,可以是根节点或某个已存在的节点。
如果新节点的父节点是根节点,则该操作称为根插入;如果新节点的父节点是已存在的节点,则该操作称为插入到指定位置。
插入操作可以通过递归或迭代方式实现。
2. 删除操作:删除操作是从二叉链表中移除一个已存在的节点。
如果被删除的节点是叶节点,则可以直接将其从链表中移除;如果被删除的节点有孩子节点,则需要先找到其孩子节点的替换节点,并将其连接到被删除节点的位置。
删除操作同样可以通过递归或迭代方式实现。
3. 查找操作:查找操作是在二叉链表中查找一个特定的值或节点。
查找操作可以通过递归或迭代方式实现,时间复杂度为O(n),其中n为二叉链表的长度。
4. 遍历操作:遍历操作是对二叉链表中的所有节点进行访问。
常见的遍历方式有前序遍历、中序遍历和后序遍历。
遍历操作可以通过递归或迭代方式实现。
5. 旋转操作:旋转操作是将二叉链表中的某个节点向左或向右移动一定的位置,以保持链表的平衡。
链表的反转与合并掌握链表反转和合并操作的实现链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。
链表的反转和合并是链表操作中常见且重要的操作,在很多编程问题中都有应用。
本文将介绍链表的反转和合并操作的实现方法。
一、链表的反转链表的反转是指将链表中节点的顺序反向排列。
例如,对于链表1→2→3→4→5,反转后的链表为5→4→3→2→1。
实现链表的反转有两种常见的方法:迭代法和递归法。
1. 迭代法迭代法的实现思路是,从链表头节点开始,依次遍历每个节点,将该节点的指针指向前一个节点。
具体步骤如下:1)定义三个指针:当前节点指针cur、前一个节点指针prev、下一个节点指针next。
2)遍历链表,将当前节点的指针指向前一个节点,然后更新prev、cur和next指针的位置。
3)重复上述步骤,直到遍历到链表末尾。
以下是迭代法的实现代码示例(使用Python语言):```pythondef reverse_list(head):prev = Nonecur = headwhile cur:next = cur.nextcur.next = prevprev = curcur = nextreturn prev```2. 递归法递归法的实现思路是,从链表的尾节点开始,依次反转每个节点。
具体步骤如下:1)递归地反转除最后一个节点外的链表。
2)将当前节点的指针指向前一个节点。
3)返回反转后的链表的头节点。
以下是递归法的实现代码示例(使用Python语言):```pythondef reverse_list(head):if not head or not head.next:return headnew_head = reverse_list(head.next)head.next.next = headhead.next = Nonereturn new_head```二、链表的合并链表的合并是指将两个有序链表按照一定的规则合并成一个有序链表。
c语言链表的基本操作(1)单链表的创建// 定义单链表结构体struct Node{int data; // 节点元素值struct Node *next; // 指向下一节点的指针};// 创建单链表struct Node * list_create(){struct Node *head; // 保存头节点struct Node *p1, *p2; // 临时指针int data;// 分配新节点p1 = (struct Node *)malloc(sizeof(struct Node));p2 = p1; // 维持p1指向新节点printf("Please input data:\n");scanf("%d", &data);// 保存数据和指针p1->data = data;p1->next = NULL;if(data != 0) {// 循环录入while(data != 0) {// 分配新节点p1 = (struct Node *)malloc(sizeof(struct Node));p1->next = NULL;// 保存数据scanf("%d", &data);p1->data = data;p2->next = p1;p2 = p1;}}head = p1;printf("Single list create success!!\n");return head;}(2)单链表的插入// 向单链表插入元素void list_insert(struct Node *list){struct Node *p1, *p2;int data;printf("Please input insert data:\n");scanf("%d", &data);// 分配新节点p1 = (struct Node *)malloc(sizeof(struct Node));p1->data = data; // 保存数据p2 = list; // p2指向头指针// 查找插入位置while ((p2 != NULL) && (p2->data < data)){p1 = p2;p2 = p2->next; // 遍历单链表}if (list == p2) // 在最前面插入{p1 = p2; // p1头指针指向头结点list = p1;}// 保存插入位置p1->next = p2;// 插入新节点p1->next->next = p2->next;printf("List insert success!!\n");}(3)单链表的删除// 删除单链表中的节点void list_delete (struct Node *list){struct Node *p1, *p2;int data;printf("Please input delete data:\n");scanf("%d", &data);p1 = list;// 查找删除位置while ((p1->next != NULL) && (p1->next->data < data)) {p1 = p1->next; // 遍历单链表}// 找到要删除的节点if (p1->next->data == data){p2 = p1->next; // 保存要删除的节点p1->next = p2->next; // 指针指向要删除的下一节点// 释放要删除的节点free(p2);printf("List delete success!!\n");}else{printf("No data in list!!\n");}}(4)单链表的查找// 查找单链表中的元素void list_fetch (struct Node *list){struct Node *p;int data;p = list;printf("Please input fetch data:\n");scanf("%d", &data);// 查找插入位置while (p != NULL){if (p->data == data){printf("Fetch success!!\n");break;}p = p->next; // 指针指向下一节点}if (p == NULL){printf("No data in list!!\n");}}(5)单链表的遍历// 遍历单链表void list_traverse (struct Node *list){struct Node *p;printf("Single list traverse: \n");p = list;while (p != NULL) // 遍历单链表{printf("%d ", p->data);p = p->next;}}(6)单链表的销毁// 销毁单链表void list_destory (struct Node *list){struct Node *p;while (list != NULL){p = list; // 保存头指针list = list->next; // 移除头节点// 释放free (p);}printf("Destory list!!\n");}。
单片机多级菜单编程实现(ZT) 建立一个树状的菜单结构,用链表实现链表中包含:1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针;2、进入该菜单时需要执行的初始化函数指针3、退出该菜单时需要执行的结束函数指针4、该菜单内的按键处理函数指针数组的指针操作菜单模块需要的按键操作有:左、右、确认、退出。
采用这种办法,可以方便的添加或删减菜单。
并且只需要在其头文件中修改初始变量就可以实现,完全无须修改C文件中的任何函数。
具体结构定义我的定义,做个参考:#define MENU_HLP_EN 菜单帮助信息使能typedef struct{void (pMenuTaskInit)(void); 指向菜单任务初始化函数的指针void (pMenuTaskEnd)(void); 指向菜单任务结束函数的指针}MENU_TASK_TYP;typedef struct MenuTyp{INT8U MenuName; 菜单名称字符串WORK_MOD WorkMod; 工作状态编号MENU_TASK_TYP pMenuTask; 指向菜单任务的指针void (pTaskKeyDeal)(void); 指向菜单任务按键处理函数数组的指针#ifdef MENU_HLP_ENINT8U MenuHlp; 菜单帮助字符串#endifstruct MenuTyp pParent; 指向上层菜单的指针struct MenuTyp pChild; 指向子菜单的指针struct MenuTyp pRight; 指向右菜单的指针struct MenuTyp pLeft; 指向左菜单的指针}MENU_TYP;我根据网上的资料做的一个菜单:菜单数据结构struct KeyTabStruct{uint8 MenuIndex; 当前状态索引号uint8 MaxItems; 本级菜单最大条目数uint8 ShowLevel; 菜单显示内容uint8 PressOk; 按下回车键时转向的状态索引号uint8 PressEsc; 按下返回键时转向的状态索引号uint8 PressDown; 按下向下键时转向的状态索引号uint8 PressUp; 按下向上键时转向的状态索引号void (CurrentOperate)(); 当前状态应该执行的功能操作};uint8 MenuID; 菜单ID号uint8 MenuNextID; 下级菜单ID号CurMenuID=本菜单IDMaxMenuItem=同级菜单最大项数OkMenuID=子菜单层所对应的菜单ID,ID=999为菜单已经到底了EscMenuID=父菜单层所对应的菜单ID,ID=999为菜单已经到顶了DownMenuID=弟菜单层所对应的菜单ID,ID=999为菜单是独生子UpMenuID=兄菜单层所对应的菜单ID,ID=999为菜单是独生子CurFunction=本菜单所对应的菜单函数指针const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={CurMenuID, axMenuItem, MenuShowLevel, OkMenuID, EscMenuID, DownMenuID, UpMenuID, CurFunction{MENU_EDIT, 0, 0, MENU_DA TA_VIEW, MENU_NO, MENU_NO, MENU_NO, MenuEdit}, {MENU_DA TA_VIEW, 3, 1, MENU_DA TA_VIEW_FIRE, MENU_EDIT, MENU_SYS_EDIT, MENU_PRINT_DA TA,MenuEdit},{MENU_DA TA_VIEW_FIRE, 5, MENU_NO, MENU_NO, MENU_DA TA_VIEW, MENU_DA TA_VIEW_TROUBLE, MENU_STEP_FOLLOW, MenuDataViewIn},{MENU_DA TA_VIEW_TROUBLE, 5, MENU_NO, MENU_NO, MENU_DA TA_VIEW, MENU_DA TA_VIEW_REPEA T, MENU_DA TA_VIEW_FIRE, MenuDataViewIn},{MENU_DA TA_VIEW_REPEA T, 5, MENU_NO,MENU_NO, MENU_DA TA_VIEW, MENU_FACE_CHECK, MENU_DA TA_VIEW_TROUBLE, MenuDataV iewIn},{MENU_FACE_CHECK, 5, MENU_NO,MENU_NO, MENU_DA TA_VIEW, MENU_STEP_FOLLOW,MENU_DA TA_VIEW_REPEA T, MenuFaceCheck},{MENU_STEP_FOLLOW, 5, MENU_NO,MENU_NO, MENU_DA TA_VIEW, MENU_DA TA_VIEW_FIRE, MENU_FACE_CHECK,MenuStepFollow},{MENU_SYS_EDIT, 3,2, MENU_SUM_SET, MENU_EDIT,MENU_PRINT_DA TA, MENU_DA TA_VIEW, MenuEdit}, {MENU_SUM_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_INSULA TE,MENU_TIME_SET, MenuSumSet},{MENU_EDIT_INSULA TE, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_HZ, MENU_SUM_SET,MenuEditInsulate},{MENU_EDIT_HZ, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_LD_CONTROL,MENU_EDIT_INSULA TE, MenuEditHZ},{MENU_LD_CONTROL, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_LD_DELAY,MENU_EDIT_HZ, MenuLDControl},{MENU_LD_DELAY, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_TIME_SET,MENU_LD_CONTROL, MenuLDDelay},{MENU_TIME_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_SUM_SET, MENU_LD_DELAY,MenuTimeSet},{MENU_PRINT_DA TA, 3, 3,MENU_PRINT_DA TA_FIRE, MENU_EDIT, MENU_DA TA_VIEW, MENU_SYS_EDIT, MenuEdit},{MENU_PRINT_DA TA_FIRE, 4,MENU_NO, MENU_NO, MENU_PRINT_DA TA,MENU_PRINT_DA TA_TROUBLE, MENU_PRINT_SET, MenuPrintDataIn}, {MENU_PRINT_DA TA_TROUBLE, 4, MENU_NO,MENU_NO, MENU_PRINT_DA TA, MENU_PRINTER_CHECK,MENU_PRINT_DA TA_FIRE, MenuPrintDataIn},{MENU_PRINTER_CHECK, 4, MENU_NO,MENU_NO, MENU_PRINT_DA TA, MENU_PRINT_SET,MENU_PRINT_DA TA_TROUBLE, MenuPrintDataIn},{MENU_PRINT_SET, 4, MENU_NO,MENU_NO, MENU_PRINT_DA TA, MENU_PRINT_DA TA_FIRE, MENU_PRINTER_CHECK, MenuPrintSet},};编程菜单显示数据const struct MenuDispData MenuEditShow[][MENU_MAX] = {{{MENU_NO , 0, 0, 选择消音→退出}, 主菜单{MENU_DA TA_VIEW , 1, 6, ⒈数据查看},{MENU_SYS_EDIT , 2, 6, ⒉系统编程},{MENU_PRINT_DA TA, 3, 6, ⒊数据打印}},{{MENU_NO , 0, 0, 数据查看消音→退出}, 数据查看{MENU_DA TA_VIEW_FIRE , 1, 4, ⒈火警},{MENU_DA TA_VIEW_TROUBLE, 2, 4, ⒉故障},{MENU_DA TA_VIEW_REPEA T , 3, 4, ⒊重码},{MENU_FACE_CHECK , 1,12, ⒋面板检测},{MENU_STEP_FOLLOW , 2,12, ⒌单步跟踪}},{{MENU_NO , 0, 0, 系统编程消音→退出}, 系统编程{MENU_SUM_SET , 1, 0, ⒈容量设置},{MENU_EDIT_INSULA TE , 2, 0, ⒉隔离点},{MENU_EDIT_HZ , 3, 0, ⒊汉字描述},{MENU_LD_CONTROL , 1,12, ⒋联动控制},{MENU_LD_DELAY, 2,12, ⒌模块延时},{MENU_TIME_SET , 3,12, ⒍时钟调整}},{{MENU_NO , 0, 0, 数据打印消音→退出}, 数据打印{MENU_PRINT_DA TA_FIRE , 1, 0, ⒈火警数据},{MENU_PRINT_DA TA_TROUBLE,2, 0, ⒉故障数据},{MENU_PRINTER_CHECK , 3, 0, ⒊打印机自检},{MENU_PRINT_SET , 1,12, ⒋打印设置}},};等待按键void WaitKey(void){uint32 time;time = RTCFlag;WhichKey = KEY_NONE;while(!EscFlag){if(RTCFlag - time = EDIT_TIME)EscFlag = TRUE;if(WhichKey != KEY_NONE){KeySound(300); 按键音return;}}}显示多级菜单void MenuEdit(){uint32 i,j=0;uint32 oldid;j = KeyTab[MenuID].ShowLevel;if(WhichKey == KEY_ESC WhichKey == KEY_OK){ClearScreen();for(i=0;iKeyTab[MenuNextID].MaxItems+1;i++)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j] [i].Column,MenuEditShow[j][i].Pdata,0); 初始化显示oldid =0;没有原先选择的项}else{if(WhichKey == KEY_UP)oldid = KeyTab[MenuNextID].PressDown;elseoldid = KeyTab[MenuNextID].PressUp;指示原先的项}for(i=1;iKeyTab[MenuNextID].MaxItems+1;i++){if(MenuEditShow[j][i].Id == oldid)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j] [i].Column,MenuEditShow[j][i].Pdata,0); 正常显示原先的项else{if(MenuEditShow[j][i].Id == MenuNextID)ShowString(MenuEditShow[j][i].Lin,MenuEditShow [j][i].Column,MenuEditShow[j][i].Pdata,1); 反显当前选择的项}}WhichKey = KEY_NONE;}系统编程uint32 Edit(void){struct KeyTabStruct NowKeyTab; 指示当前的菜单值uint32 escflag = FALSE;ResetFlag = FALSE;ChangeFlag = FALSE;EscFlag = FALSE;MenuID = MENU_EDIT;NowKeyTab = KeyTab[MenuID];MenuNextID = NowKeyTab.PressOk;(NowKeyTab.CurrentOperate)(); 显示主菜单do{if(WhichKey == KEY_NONE)WaitKey(); 等待按键switch(WhichKey){case KEY_ESC if(NowKeyTab.PressEsc != MENU_NO) {MenuID =NowKeyTab.PressEsc;MenuNextID =NowKeyTab.MenuIndex;NowKeyTab = KeyTab[MenuID];NowKeyTab.PressOk =MenuNextID;(NowKeyTab.CurrentOperate) (); 显示当前菜单}elseescflag =TRUE; 退出编程状态break;case KEY_OK if(NowKeyTab.PressOk != MENU_NO){MenuID =NowKeyTab.PressOk;NowKeyTab = KeyTab[MenuID];MenuNextID =NowKeyTab.PressOk;}(NowKeyTab.CurrentOperate)(); 执行当前按键的操作break;case KEY_UP if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressUp != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressUp;MenuNextID = KeyTab[MenuNextID].PressUp;(NowKeyTab.CurrentOperate)(); 执行当前按键的操作}break;case KEY_DOWN if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressDown != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressDown;MenuNextID = KeyTab[MenuNextID].PressDown;(NowKeyTab.CurrentOperate)(); 执行当前按键的操作}break;case KEY_RESET ResetFlag = TRUE;break;default break;}}while(!ResetFlag && !EscFlag && !escflag);if(ChangeFlag && !EscFlag && !ResetFlag)EditDataChange();if(ResetFlag)return SYS_RESET;else{return 0;}}关于这个菜单的说明:1.我用的是ARM处理器,所以51的时候把const改成code,uint32改成unsigned char。