目录
(一)需求分析: 3
(二)概要设计: 3
(三)详细设计: 4
1)实现链表指针创建功能 4
2)链表创建函数 4
3)链表显示函数 5
4)查找链表指定元素函数 5
5)删除链表指定元素 6
6)实现删除链表功能的函数 7
7)实现链表合并的功能函数 7
8)实现增加新节点的功能函数。 8
9)实现链表排序的功能函数。 9
10)实现链表文件读取的功能函数 10
11)实现链表文件存储的功能函数。 11
12)实现菜单选择的功能函数。 11
(四)系统演示及使用说明 12
1).菜单选项 12
2).创建链表 12
3).显示链表 12
4).查找指定的链表元素 13
5).删除指定的链表元素 13
6).删除链表 13
7).链表合并 13
8).链表元素的排序 14
9).添加指定位置的新节点 14
10).读取链表文件 14
11).文件存储链表 15
12).退出程序 15
13).非法输入 15
(五)心得体会 16
(六)附录:链表管理系统源代码。 16
(一)需求分析:
根据任务要求,该系统可以实现对链表相应操作的管理,相应的函数应该可以实现创建链表、显示链表、查找指定的链表元素、删除指定的链表元素、删除链表、链表合并、链表元素排序、添加指定位置的新节点……等。
另外,该系统还可以实现在文件中读取链表的数据产生链表,同时可以将用户输入的链表保存到文件中,方便链表的操作和管理。
输入:链表管理系统提供选项菜单,用户可以根据自身需要进行选择,完成对链表的相应操作,可以实现实现创建链表、显示链表、查找指定的链表元素、删除指定的链表元素、删除链表、链表合并、链表元素排序、添加指定位置的新节点、读取链表文件、文件存储链表、退出程序的功能。
输出/结果:根据用户的选择,输出对应功能的结果,在用户需要的时候还可以把相应的信息存入文件中。
(二)概要设计:
(三)详细设计:
1)实现链表指针创建功能
功能:定义指针的数据域和指针域,明确指针形式。
参数说明:
num:结构参数,int类型,用于指针数据域创建。
next:结构参数,struct node *类型,用于连接指针的指针域。
返回值:无。
算法:
typedef struct node{
int num;
struct node *next;
}Node;
2)链表创建函数
功能:根据用户输入创建一个链表。
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Last:功能参数,Node类型链表指针,用于指向链表尾部。
Num:输入参数,int类型,用于读取用户输入的数据存入链表节点中。
P:功能参数,Node类型链表指针,帮助构建新链表。
返回值:Head
算法:
4)查找链表指定元素函数
功能:根据用户输入,查找链表是否存在指定元素。
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Num:传入参数,int类型,传入函数用户想要查找的元素。
Sum:功能参数,int类型初始值等于1,累加器记录查找元素的位置。
Flag:功能参数,int类型,通过值是否发生变化判断输入数据。
返回值:无。
算法:
5)删除链表指定元素
功能:根据用户输入删除指定的元素。
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Num:传入参数,int类型,传入函数用户想要删除的元素。
P:功能参数,Node类型链表指针,用于保存q->next链接链表;
q:功能参数,Node类型链表指针,用于遍历链表。
i:功能参数,int类型,用于控制for循环。
返回值:head
算法:
6)实现删除链表功能的函数
功能:删除用户输入的链表
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
P:功能参数,Node类型链表指针,用于保存q->next链接链表;
q:功能参数,Node类型链表指针,用于遍历链表。
i:功能参数,int类型,用于控制for循环。
返回值:无。
算法:
7)实现链表合并的功能函数
功能: 将用户输入的两个链表合并起来。
参数说明:
Head1:传入参数,Node类型链表指针,指向链表的头部。
Head2:传入参数,Node类型链表指针,指向链表的头部。
P1:功能参数,Node类型链表指针,遍历head1链表。
P2:功能参数,Node类型链表指针,遍历head2链表。
Head_new: 传出参数,Node类型链表指针,合并之后的新链表。
Last:功能参数,Node类型链表指针,用于尾插法创建新链表。
返回值:Head_new
算法:无。
8)实现增加新节点的功能函数。
功能: 根据用户输入增加新节点。
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Num:传入参数,int类型,传入新节点数据域的值。
M:传入参数,int类型,传入新节点插入的位置。
Last:功能参数,Node类型链表指针,用于遍历链表。
P:功能参数,Node类型链表指针,用于创建新节点。
Len:功能参数,int类型,用于计算head链表长度。
Flag:功能参数,int类型,通过值是否发生变化判断节点是否创建成功。
返回值:head
算法:
9)实现链表排序的功能函数。
功能:对用户输入的链表进行由小至大的排序。
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Head_new:功能参数,Node类型链表指针,用于保存排序后的链表
Last:功能参数,Node类型链表指针,用于尾插法创建新链表。
P:功能参数,Node类型链表指针,用于遍历链表head。
Min:功能参数,Node类型链表指针,找到每次循环的最小值节点
Beforemin:功能参数,Node类型链表指针,找到每次循环的最小值节点的前一个节点。
返回值:Head_new
算法:
10)实现链表文件读取的功能函数
功能: 读取存在于文件中的链表
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Last:功能参数,Node类型链表指针,用于遍历链表。
Num;功能参数,int类型,读取文件中的数据。
返回值:head
算法:
11)实现链表文件存储的功能函数。
功能:
参数说明:
head:传入参数,Node类型链表指针,指向链表的头部。
Last:功能参数,Node类型链表指针,用于遍历链表。
返回值:head
算法:
12)实现菜单选择的功能函数。
功能:提供用户管理链表的菜单选择界面。
参数说明:
Ch:输入参数,int类型,读取用户选择的功能选项。
返回值:无。
算法:无。
(四)系统演示及使用说明
1).菜单选项
为用户提供菜单选择对应功能即可。
2).创建链表
选择1,根据提示输入数据,并用0结尾表示输入完成,提示链表创建成功。
3).显示链表
输入2,显示已经创建的链表。
4).查找指定的链表元素
输入3,在输入想要查找的数据,显示数据所处的位置。
5).删除指定的链表元素
输入4,在输入想要删除的节点位置,提示删除成功。
6).删除链表
输入5,链表的节点依次释放。
7).链表合并
输入6,在根据提示输入另一个链表。显示两个链表合并完成的新链表
8).链表元素的排序
首先创建新的乱序链表,选择功能7,进行排序,通过2判断链表排序成功。
9).添加指定位置的新节点
选择功能8,依次输入添加的元素和位置,提示添加成功,功能2验证成功。
10).读取链表文件
读取相对路径下的 List.txt的文件,生成链表
11).文件存储链表
选择功能10将输入的链表保存到文件中
12).退出程序
输入0,结束程序。
13).非法输入
输入0-10外的其他的数据,将提示错误,并从新输入。
(五)心得体会
本次课程,我主要学习的是没有头结点的,即只有一个头指针,在写代码的时候我总是会把头指针误认为一个头结点,然后定义另一个指针来存储这个头指针,其实有时候是没有必要的,虽然不影响操作。头指针是指向第一个节点的指针,而头结点是一个只有next指针而没有数据的节点,因此两者其实差不多,只是头指针可以任意移动,而头结点需要定义一个指针来指向我们的头结点,存储当前位置。在进行链表的删除节点的操作时,遇到的问题就是我的头指针必须指向第一个节点,因此我必须定义两个指针来指向头指针,即二重指针,这样才能方便我存储要删除的节点的位置。
内存泄漏指:由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存溢出指:应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存,一般我们在玩游戏时,电脑内存或者手机内存不够用了,则会发现游戏会自动强制退出,等待一部分内存释放之后我们又可以进入游戏。由此我又重新梳理了一遍程序,在相关函数中及时释放掉不使用的内存,减少对系统资源的利用
我认为链表其实并不难,重点在于要有明确的逻辑思路,能够清晰的捋顺节点与节点的关系,我学习的方法是利用画图来解决问题,把每一个节点都画出来找到节点和节点之间的关系,就变得很简单。
在未来的学习生活中,我一定勤思考,多动手,实践是检验真理的唯一标准,有什么问题和想法一定要自己动手。纸上学来终觉浅,觉知此事要躬行!只有真真正正的完成了这次设计,我认识到了自己的很多不足,也明确了实践的重要性。
最后感谢,程序设计课的任课老师-魏老师。上课讲解的十分透彻,熬夜为学生解答问题,让我深受感动,感谢魏**老师的无私付出!
(六)附录:链表管理系统源代码。
#include
#include
typedef struct node{
int num;
struct node *next;
}Node;
//创建链表
Node *createList(Node *head){
Node *last = head;
int num ;
printf("请输入数据:\n");
while(1){
scanf("%d",&num);
Node *p = (Node *)malloc(sizeof(Node));
p->num = num;
p->next = NULL;
if(num == 0){
break;
}else{
if(head != NULL){
last->next = p;
last = p;
}else{
head = last = p;
}
}
}
printf("您输入的链表已经创建成功!\n");
return head;
}
//显示链表
Node *showList(Node *head){
Node *last = head;
printf("您使用的链表为:\n");
while(last != NULL)
{
printf("%d,",last->num);
last = last->next;
}
printf("\n");
return head;
}
//查找指定元素
Node *seekNum(Node *head,int num){
int sum = 1,flag = 0;
while(head != NULL)
{
if(head->num == num)
{
flag = 1;
break;
}
head = head->next;
sum++;
}
if(flag == 1)
printf("数据位于第%d位!\n",sum);
else
printf("数据不存在!\n");
}
//删除指定元素
Node *deleteNum(Node *head,int num){
Node *p;
Node *q = head;
int i;
if(q->next !=NULL && num>1){
p=q->next;
q->next = p->next;
free(p);
}
for(i=0; i<num-1 && head->next != NULL; ++i){
q = q->next;
}
printf("该元素已经成功删除!\n");
return head;
}
//删除链表
Node *deleteList(Node *head){
Node *q=head;
Node *p=NULL;
int i=1;
while(q){
p=q;
q=q->next;
free(p);
printf("%d is free\n",i++);
}
}
//链表合并
Node *mergeList(Node *head1,Node *head2){
Node *p1 = head1;
Node *p2 = head2;
Node *head_new = NULL;
Node *last = head_new;
Node *p ;
while(p1 && p2){
p = (Node*)malloc(sizeof(Node));
if(p1->num >p2->num){
p->num= p2->num;
p->next = NULL;
if(head_new == NULL){
head_new = last = p;
}else{
last->next = p;
last = p;
}
p2 = p2->next;
}else if(p1->num < p2->num){
p->num = p1->num;
p->next = NULL;
if(head_new == NULL){
head_new = last = p;
} else{
last->next = p;
last = p;
}
p1 = p1->next;
}else{
p->num = p2->num;
p->next = NULL;
if(head_new == NULL){
head_new = last = p;
}else{
last->next = p;
last = p;
}
p1 = p1->next;
p2 = p2->next;
}
}
while(p2){
p = (Node*)malloc(sizeof(Node));
p->num = p2->num;
p->next = NULL;
last->next = p;
last = p;
p2 = p2->next;
}
while(p1){
p = (Node*)malloc(sizeof(Node));
p->num = p1->num;
p->next = NULL;
last->next = p;
last = p;
p1 = p1->next;
}
return head_new;
}
//增加新节点
Node *addNum(Node *head,int num ,int m){
Node *last = head;
Node *p ;
int len;
int flag = 0;
for( len=0;last!=NULL;len++){
last = last->next;
}
last = head;
if(m == 1){
p = (Node*)malloc(sizeof(Node*));
p->num = num;
p->next = head;
head = p;
flag = 1;
}else{
if(m<len+1 || m==len+1){
for(int i=1;i<m-1;i++){
last = last->next;
}
p = (Node*)malloc(sizeof(Node*));
p->num = num;
p->next = last->next;
last->next = p;
flag = 1;
}
else
printf("您的输入错误!\n");
}
if(flag = 1)
printf("结点添加完成\n");
return head;
}
//链表排序
Node *sortList(Node *head){
Node *head_new = NULL;
Node *last = head_new;
Node *p = head;
Node *min = head;
Node *beforemin;
while(head){
for(p = head,min = head;p->next != NULL;p=p->next){
if(p->next->num < min->num){
min = p->next;
beforemin = p;
}
}
if(min == head){
head = min->next;
}else{
beforemin->next = min->next;
}
if(head_new == NULL) {
head_new = last = min;
} else{
last->next = min;
last = min;
}
}
printf("链表元素排序成功!\n");
return head_new;
}
//读取文件展的数据,形成链表
Node *readList(Node *head){
Node *last = head;
int num;
FILE *fp = fopen("List.txt","r");
if(fp == NULL){
printf("文件打开失败!\n");
return NULL;
}
while(fscanf(fp,"%d",&num) != EOF)
{
Node*p = (Node*)malloc(sizeof(Node));
p->num = num;
p->next = NULL;
if(head == NULL){
head = last = p;
}
else{
last->next = p;
last = p;
}
}
fclose(fp);
printf("文件读取成功!\n");
return head;
}
//保存链表
Node *writeList(Node *head){
Node *last = head;
FILE *fp =fopen("List.txt","w");
if(fp == NULL){
printf("文件打开失败!\n");
return NULL;
}
while(last){
fprintf(fp,"%d\n",last->num);
last = last->next;
}
printf("文件保存成功!\n");
fclose(fp);
}
int main (){
Node *head = NULL;
int ch; //菜单选项
int seek; //查找的数
int dele;//删除的元素的位置
int num ,m,n;
printf("****************************\n");
printf("*--欢迎使用链表管理系统!--*\n");
while(1){
printf("****************************\n");
printf("*1----创建链表 *\n");
printf("*2----显示链表 *\n");
printf("*3----查找指定的链表元素 *\n");
printf("*4----删除指定的链表元素 *\n");
printf("*5----删除链表 *\n");
printf("*6----链表合并 *\n");
printf("*7----链表元素排序 *\n");
printf("*8----添加指定位置的新节点 *\n");
printf("*9----读取链表文件 *\n");
printf("*10---文件存储链表 *\n");
printf("*0----退出程序 *\n");
printf("****************************\n");
printf("*-----请输入选项-----------*\n");
scanf("%d",&ch);
switch(ch){
case 1:
head = createList(head);
break;
case 2:
showList(head);
break;
case 3:
printf("请输入您要查找的数据:");
scanf("%d",&seek);
seekNum(head,seek);
break;
case 4:
printf("请输入删除元素的位置:");
scanf("%d", &dele);
head =deleteNum(head,dele);
break;
case 5:
deleteList(head);
break;
case 6:
printf("请输入另一条需要合并的链表\n");
Node *head_2 = NULL;
head_2 = createList(head_2);
head_2 = mergeList(head,head_2);
showList(head_2);
printf("链表合并完成!\n");
break;
case 7:
head = sortList(head);
break;
case 8:
printf("-请输入您想添加的元素\n");
scanf("%d",&num);
printf("-请输入您想要添加的结点的位置-\n");
scanf("%d",&m);
head = addNum(head,num,m);
break;
case 9:
readList(head);
break;
case 10:
writeList(head);
break;
case 0:
printf("程序已结束,欢迎下次使用!\n");
return 0;
default:
printf("输入错误,请重新输入!\n");
break;
}
}
}