题目内容
在上次练习的的基础上实现“单链表”的合并有序数据
【要求:数据元素(ElemType)为结构体类型(如:Student,成员包括——学号、姓名、成绩等 )】
个人解法
1.自定义的头文件
#include#include #define M 33 #define N 99 //开始菜单 void menu() { printf(" 欢迎访问学生管理系统n"); printf("n"); printf(" 01、添加学生信息n"); printf(" 02、已录入学生数n"); printf(" 03、显示学生信息n"); printf(" 04、查看学生序号n"); printf(" 05、查看学生信息n"); printf(" 06、插入学生信息n"); printf(" 07、删除学生信息n"); printf(" 08、清空录入数据n"); printf(" 09、销毁录入数据n"); printf(" 10、合并链表数据n"); printf(" 11、退出管理系统n"); printf("n"); printf(" 请输入指令(1 - 11)n"); } //建立结构体类型“学生” typedef struct { unsigned int id; //学号 char gender[M]; //性别 char name[M]; //名字 float score; //分数 }Student; //建立单链表存储结构 typedef struct LNode { Student data; //数据域 struct LNode* next; //指针域 }LNode, * LinkList; //初始化链表 void InitList_LinkList(LinkList& L) { L = (LNode*)malloc(sizeof(LNode)); if (L != NULL) //IDE能够察觉到我们用malloc申请空间的时候可能会存在失败的情况,所以我们要加个空指针判断 L->next = NULL; } //尾插法创建链表(添加学生信息) void CreateList_LinkList(LinkList& L) { LinkList rear = L, p; //尾指针rear指向生成的头结点 int number; printf("请输入待添加的学生人数:n"); scanf("%d", &number); printf("请输入这%d名学生的学号、性别、名字、分数:n", number); for (int i = 0; i < number; i++) { p = (LNode*)malloc(sizeof(LNode)); //生成新结点 if (p != NULL && rear != NULL) { getchar(); //清理缓存 scanf("%d %s %s %f", &p->data.id, &p->data.gender, &p->data.name, &p->data.score); p->next = NULL; //next域初值为空 rear->next = p; //插入到表尾 rear = p; //rear指向新的尾结点 } } rear->next = NULL; //尾结点置为空 } //获取链表中数据元素个数(已录入学生数) void GetLength_LinkList(LinkList& L) { LinkList p; //指针p为指点工具 int time = 0; //time为计数器 p = L->next; //p指向第一个结点 while (p != NULL) //遍历单链表,统计结点数 { time++; p = p->next; } printf("当前数量为:%dn", time); } //输出链表(显示学生信息) void PrintList_LinkList(LinkList& L) { LinkList p; if (!L) printf("n链表不存在!"); else { p = L->next; if (p == NULL) printf("n链表为空!"); else printf("该链表的元素有:n"); while (p != NULL) { printf("%d %s %s %.2fn", p->data.id, p->data.gender, p->data.name, p->data.score); p = p->next; } } } //获取链表中数据元素位置(查看学生序号) void LocateElem_LinkList(LinkList& L) { LinkList p; int type, id, n = 1; char name[M]; p = L->next; printf("请选择检索方式(1 - 3):n1.学号 2.名字 3.其它n"); scanf("%d", &type); switch (type) { case 1: printf("请输入目标学生的学号:n"); scanf("%d", &id); while (p != NULL && p->data.id != id) { p = p->next; n++; } break; case 2: printf("请输入目标学生的名字:n"); scanf("%s", &name); while (p != NULL && strcmp(p->data.name, name) != 0) { p = p->next; n++; } break; case 3: printf("功能仍在开发中,敬请期待!n"); break; default: printf("指令项不存在,请重新选择!n"); break; } if (p != NULL) printf("学生序号为:%dn", n); else printf("查无此人!"); } //获取链表中数据元素值(查看学生信息) void GetElem_LinkList(LinkList& L) { LinkList p; int type, id, n = 1; char name[M]; p = L->next; printf("请选择检索方式(1 - 3):n1.学号 2.名字 3.其它n"); scanf("%d", &type); switch (type) { case 1: printf("请输入目标学生的学号:n"); scanf("%d", &id); while (p != NULL && n < id) { if (p->data.id != id) { p = p->next; ++n; } else { printf("学生信息为:n%d %s %s %.2fn", p->data.id, p->data.gender, p->data.name, p->data.score); break; } } if (p == NULL || n > id) printf("查无此人!"); break; case 2: printf("请输入目标学生的名字:n"); scanf("%s", &name); while (p != NULL) { if (strcmp(p->data.name, name) != 0) { p = p->next; ++n; } else { printf("学生信息为:n%d %s %s %.2fn", p->data.id, p->data.gender, p->data.name, p->data.score); break; } } if (p == NULL || strcmp(p->data.name, name) != 0) printf("查无此人!"); break; case 3: printf("功能仍在开发中,敬请期待!n"); break; default: printf("指令项不存在,请重新选择!n"); break; } } //在链表中插入数据元素(插入学生信息) void ListInsert_LinkList(LinkList& L) { LinkList p = L, q; int n, time = 0; //计数器time置0是考虑到time==1的情况 printf("请输入欲插入的位置:n"); scanf("%d", &n); while (p != NULL && time < n - 1) //寻找第n-1个结点以定值p { p = p->next; ++time; } if (p == NULL || time > n - 1) //考虑n<1||n>表长+1的情况 printf("位置有误!"); printf("请输入欲插入的学生的的学号、性别、名字、分数:n"); q = (LNode*)malloc(sizeof(LNode)); //生产新结点q getchar(); scanf("%d %s %s %f", &q->data.id, &q->data.gender, &q->data.name, &q->data.score); q->next = p->next; //插入到链表中 p->next = q; } //在链表中删除数据元(删除学生信息) void ListDelete_LinkList(LinkList& L) { LinkList p = L, q; int confirm, n, time = 0; printf("请输入欲删除的位置:n"); scanf("%d", &n); while (p != NULL && time < n - 1) //寻找第n个结点,并令p指向其前趋 { p = p->next; ++time; } if (p == NULL || time > n - 1) //删除位置不合理 printf("位置有误!"); q = p->next; //删除并释放结点 p->next = q->next; printf("删除成功,是否执行撤销操作(1/2):n1.是 2.否n"); scanf("%d", &confirm); if (confirm == 1) { q->next = p->next; p->next = q; printf("撤销成功!"); } else free(q); } //清空链表 void ClearList_LinkList(LinkList& L) { LinkList p, q; p = L->next; //p指向第一个节点 while (p != NULL) //没到表尾 { q = p->next; free(p); p = q; } L->next = NULL; //头结点指针域为空 } //销毁链表 void DestroyList_LinkList(LinkList& L) { LinkList p; while (L) { p = L; L = L->next; free(p); } } //合并(有序)链表 LNode* MergeList_LinkList(LinkList La, LinkList Lb) { LinkList Lc; Lc = (LinkList)malloc(sizeof(LNode)); LinkList pa, pb, pc; pa = La->next; //pa,pb指针分别指向两个已知的表的第一个结点 pb = Lb->next; pc = Lc; //p指向L的头结点 while (pa != NULL && pb != NULL) //依次将小的数尾插到新链表上 { if (pa->data.id <= pb->data.id) { pc->next = pa; pc = pa; pa = pa->next; } else { pc->next = pb; pc = pb; pb = pb->next; } } pc->next = pa ? pa : pb; //最后必有某个原链表还剩下一串链表节点,直接尾插在新链表上 La->next = NULL; Lb->next = NULL; return Lc; }
2.源文件(注意源文件内调用的头文件名须与自定义的头文件名相同)
#define _CRT_SECURE_NO_WARNINGS //防报错 #include#include "LinkList.h" //主函数 int main() { system("color 3"); LinkList L[N]; int Choice, ListNumber, flag = 0; printf("请输入预计需使用的链表数:n"); scanf("%d", &ListNumber); for (int i = 0; i < ListNumber; i++) //对所有预备链表进行初始化操作,在每次成功后flag自增 { InitList_LinkList(L[i]); ++flag; } if (flag == ListNumber) //若flag自增结果和预备链表数相等,则说明初始化全部成功 { while (1) { system("cls"); menu(); scanf("%d", &Choice); switch (Choice) { case 1: int CreateListNumber; printf("请输入欲创建的链表编号(1 - %d):n", ListNumber); scanf("%d", &CreateListNumber); CreateList_LinkList(L[CreateListNumber - 1]); printf("n当前操作已结束!"); break; case 2: int GetLengthNumber; printf("请输入欲查长的链表编号(1 - %d):n", ListNumber); scanf("%d", &GetLengthNumber); GetLength_LinkList(L[GetLengthNumber - 1]); printf("n当前操作已结束!"); break; case 3: int PrintListNumber; printf("请输入欲输出的链表编号(1 - %d):n", ListNumber); scanf("%d", &PrintListNumber); PrintList_LinkList(L[PrintListNumber - 1]); printf("n当前操作已结束!"); break; case 4: int LocateElemNumber; printf("请输入欲查值的链表编号(1 - %d):n", ListNumber); scanf("%d", &LocateElemNumber); LocateElem_LinkList(L[LocateElemNumber - 1]); printf("n当前操作已结束!"); break; case 5: int GetElemNumber; printf("请输入欲取值的链表编号(1 - %d):n", ListNumber); scanf("%d", &GetElemNumber); GetElem_LinkList(L[GetElemNumber - 1]); printf("n当前操作已结束!"); break; case 6: int ListInsertNumber; printf("请输入欲插值的链表编号(1 - %d):n", ListNumber); scanf("%d", &ListInsertNumber); ListInsert_LinkList(L[ListInsertNumber - 1]); printf("n当前操作已结束!"); break; case 7: int ListDeleteNumber; printf("请输入欲删值的链表编号(1 - %d):n", ListNumber); scanf("%d", &ListDeleteNumber); ListDelete_LinkList(L[ListDeleteNumber - 1]); printf("n当前操作已结束!"); break; case 8: int ClearListNumber; printf("请输入欲清空的链表编号(1 - %d):n", ListNumber); scanf("%d", &ClearListNumber); ClearList_LinkList(L[ClearListNumber - 1]); printf("n已清空录入数据!"); break; case 9: int DestroyListNumber; printf("请输入欲销毁的链表编号(1 - %d):n", ListNumber); scanf("%d", &DestroyListNumber); DestroyList_LinkList(L[DestroyListNumber - 1]); printf("n已销毁录入数据!"); break; case 10: int MergeListNumber1, MergeListNumber2; printf("请输入欲合并的两链表编号(1 - %d):n", ListNumber); scanf("%d %d", &MergeListNumber1, &MergeListNumber2); L[++ListNumber - 1] = MergeList_LinkList(L[MergeListNumber1 - 1], L[MergeListNumber2 - 1]); //注意这里ListNumber须自增以正确对应新链表 printf("n已合并链表数据!"); break; case 11: printf("n已退出管理系统!"); exit(0); default: printf("n指令项不存在,请重新选择!"); break; } system("pause"); printf("n缓存已全部清除!"); } } else printf("链表初始化失败!n"); return 0; }
运行结果:
本人拙作,请大佬们点评。



