当前位置: 首页 > news >正文

数据结构学习(2)——多功能链表的实现(C语言)

上次我们讲到了如何创建一个普通的链表,今天我们将优化这个链表,使其拥有添加数据、插入数据、删除数据、查找数据、替换数据、退出程序等功能,成为一个较为完整的链表。

思维搭建

由于需要实现的功能较多,我们应该想到将各个功能封装成一个个函数,并给每个功能标上编号,根据用户输入的编号在主函数中调用对应的函数,实现对应的功能。同时在创建链表方面,一个节点需要保存下一个节点的位置和当前节点的数据,因此需要创建一个结构体(详细见上一篇博客),再依次将数据保存、相连,得到一个链表。

实现步骤

一、输出提示语句,获取用户输入的功能编号

我们可以在主函数中根据自己的定义方法输出一系列语句,提示用户各种功能对应的编号,并且获取键盘的输入值。同时需要注意的是:我们需要实现的效果是每次完成一个功能,就要再弹出一次这些提示语句和输入功能编号,所以我们需要用while关键字写一个死循环(1在C语言中代表true,所以一直都会通过)。

	while (1) {printf("功能编号列表:\n");printf("==101:在末尾添加元素\n");printf("==102:在指定位置添加元素\n");printf("==103:替换指定位置的元素\n");printf("==201:打印链表中的数据\n");printf("==301:删除元素\n");printf("==501:查找一个指定的位置的元素\n");printf("==502:查找一个指定的元素的位置\n");printf("==601:清空链表\n");printf("==999:退出程序\n");printf("请输入功能编号:\n");int cid;scanf("%d", &cid);
}

二、书写一个链表的结构体

我们在上一篇博客中提到了创建一个链表的方法,需要一个节点结构体包含data和next属性。(详见上一篇博客)

//节点结构体
struct ListNode {int data;ListNode *next;
};

三、书写每个功能对应的函数

1、创建新节点

由于在许多功能中都涉及到创建一个新节点的操作,我们不妨把这个操作包装成一个函数,在需要创建时直接调用即可,不需要重复书写相同的代码,使代码更加简洁。

该函数的返回值应该是一个节点(指针类型),也就是上面结构体的类型ListNode,需要的参数是data(该节点对应的数据)。我们给这个新节点分配一块空间后,将入的参数赋值该节点的data,并将下一个节点设为NULL,并返回这个节点就可以创建一个新的节点了。

ListNode *createNode(int data) {ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));newNode->data = data;newNode->next = NULL;return newNode;
}

2、在末尾添加元素

这与上篇博客提到的实现方法一致,书写一个返回值为ListNode的函数,需要传入参数有:data(添加的数据)、head(头节点)。注:几乎所有的操作都需要头节点,因为这是操作链表的唯一入口。利用我们刚写好的函数创建一个新的节点,并单独写判断语句排除节点创建失败空链表的情况,然后建立一个临时的变量保存头节点(防止头节点被改变),然后开始对这个*temp进行类似于遍历的操作,知道*temp的下一个为空(说明到末尾了),就退出循环。最后,将temp的下一个赋值为新节点newNode即可。(最后记得返回头节点

ListNode *add(int data, ListNode *head) {ListNode *newNode = createNode(data);if (newNode == NULL) {printf("新节点创建失败,无法分配内存~");return head;}if (head == NULL) { //说明是空链表return newNode;}ListNode *temp = head;while (temp->next != NULL) {temp = temp->next;}//循环结束后,temp是最后一个节点,要将新的节点加载到它的后面temp->next = newNode;return head;
}

3、在指定位置添加元素

基本与在末尾添加一致,不过参数还需要index,明确需要插入的位置(在这里我们以插入index后面为例)。

我们还需要一个计数变量,让其每次都递增,直到它等于index(说明找到位置了),在尚未等于index时都需要将temp赋值为下一个。

找到位置后,将temp在index位置的下一个赋值给新节点的下一个,将temp的下一个赋值为新节点。(可以通过画示意图来理解)

ListNode *insert(int index, int data, ListNode *head) {ListNode *newNode = createNode(data);if (newNode == NULL) {printf("新节点创建失败,无法分配内存~");return head;}if (head == NULL) { //说明是空链表return newNode;}ListNode *temp = head;int count = 0;while (temp->next != NULL) {if (count == index) {newNode->next = temp->next;temp->next = newNode;break;}temp = temp->next;//没通过判断就继续递增,直到等于indexcount++;}return head;
}

4、替换指定位置的元素

与插入元素类似,只不过不是创建一个新的节点插入,而是直接更改该节点的数据,不需要操作指针。

ListNode *replace(int index, int data, ListNode *head) {int count = 0;ListNode *cur = head;while (cur != NULL && count < index) {cur = cur->next;count++;}cur->data = data;return head;
}

5、打印链表中的数据

这个功能其实在每一次执行完一个功能后都应该调用一次,来显示出操作的效果。

这个功能不需要返回值,同样是利用链表的遍历方法,不断将temp赋值为下一个节点,逐个打印出该节点的元素。同时,应该有一个判断在前:如果链表为空,直接输出一个空括号[   ],防止程序因通不过下面的条件而卡在中间进程。

还有,由于在末尾的节点下一个为空,无法赋值到temp,导致最后一个元素的data打印不了,所以还应该有一个单独的输出语句打印末尾节点的数据

void printList(ListNode *head) {ListNode *temp = head;if (head == NULL) {printf("\n链表为:[]");} else {printf("\n链表为:[");while (temp->next != NULL) {printf("%d->", temp->data);temp = temp->next;}printf("%d]\n", temp->data);}
}

6、删除元素(通过下标)

需要传入的参数是index、*head。

思路应该是通过遍历到达要删除元素的位置,设置一个prev表示上一个节点,cur表示当前节点(需要保证一直有两个连续的节点可以操作)。单独书写删除头节点的情况(头节点没有上一个元素),定义一个变量保存原始的头节点,然后直接将头节点赋值为下一个节点,用free关键字清楚temp的 空间即可。注意:不可以直接free(head),否则链表就没有头节点。

若不是删除头节点,就要不断将cur往下遍历,而prev等于还没往下移动的cur,并用计数变量确定位置。到达index后,直接将cur的下一个赋值给prev的下一个,将cur的内存释放掉即可。

//通过下标删除元素
ListNode *cutByE(int index, ListNode *head) {int count = 0;if (head == NULL) {printf("链表为空,无法删除元素");}//删除头节点的情况if (index == 0) {ListNode *temp = head;head = head->next;free(temp);return head;}ListNode *prev = NULL;ListNode *cur = head;while (cur != NULL && count < index) {prev = cur;cur = cur->next;count++;}//执行删除操作prev->next = cur->next;free(cur);return head;
}

7、查找一个指定的位置的元素

给定一个参数index,通过计数变量,经过遍历到达指定位置,然后将该节点的数据返回即可。

//查找指定位置的元素
int getByi(int index, ListNode *head) {int count = 0;ListNode *temp = head;while (temp != NULL && count < index) {temp = temp->next;count++;}return temp->data;
}

8、查找一个指定的元素的位置

同样道理,不断遍历直到要求的data等于链表中某个节点的data,通过计数变量测定位置,最后返回该计数变量即可。

//查找指定元素的位置
int getByE(int data, ListNode *head) {ListNode *temp = head;int index = 0;while (data != temp->data && temp->next != NULL) {temp = temp->next;index++;}return index;
}

9、清空链表

清空链表本质就是释放内存,只需要不断遍历并将每个temp释放内存即可。

//清空链表
void clean(ListNode *head) {ListNode *cur = head;while (cur->next != NULL) {ListNode *temp = cur;cur = cur->next;free(temp);}
}

10、退出程序

使用exit关键字,参数给0即可退出程序的运行。

//推出程序
void esc() {printf("[999退出程序] 程序退出成功!");exit(0);
}

四、调用函数

在主函数中,书写一些判断语句分析用户输入的编号,调用对应的函数,给定要求的参数即可。

if (cid == 101) {printf("[101添加元素]>>请输入一个数字:");int data;scanf("%d", &data);head = add(data, head);} else if (cid == 102) {printf("[102插入元素]>>请输入插入的位置和数据:");int index, data;scanf("%d %d", &index, &data);head = insert(index, data, head);} else if (cid == 103) {printf("[103替换元素]>>请输入替换的位置和新数据:");int index, data;scanf("%d %d", &index, &data);head = replace(index, data, head);} else if (cid == 501) {printf("[501查找指定位置的元素]>>请输入所需查找的位置:");int index;scanf("%d", &index);printf("该位置的元素为:");int data = getByi(index, head);printf("%d", data);} else if (cid == 502) {printf("[502查找指定元素的位置]>>请输入所需查找的元素:");int data;scanf("%d", &data);printf("该元素的位置为:");int place = getByE(data, head);printf("%d", place);} else if (cid == 601) {printf("[601清空链表]");clean(head);head = NULL;} else if (cid == 999) {esc();} else if (cid == 301) {int index;printf("[301删除元素]>>请输入所删除数据的下标:");scanf("%d", &index);head = cutByE(index, head);}

代码展示

#include <stdio.h>
#include <stdlib.h>//节点结构体
struct ListNode {int data;ListNode *next;
};//创建新节点
ListNode *createNode(int data) {ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));newNode->data = data;newNode->next = NULL;return newNode;
}//添加元素
ListNode *add(int data, ListNode *head) {ListNode *newNode = createNode(data);if (newNode == NULL) {printf("新节点创建失败,无法分配内存~");return head;}if (head == NULL) { //说明是空链表return newNode;}ListNode *temp = head;while (temp->next != NULL) {temp = temp->next;}//循环结束后,temp是最后一个节点,要将新的节点加载到它的后面temp->next = newNode;return head;
}//将数据插入到指定的位置
ListNode *insert(int index, int data, ListNode *head) {ListNode *newNode = createNode(data);if (newNode == NULL) {printf("新节点创建失败,无法分配内存~");return head;}if (head == NULL) { //说明是空链表return newNode;}ListNode *temp = head;int count = 0;while (temp->next != NULL) {if (count == index) {newNode->next = temp->next;temp->next = newNode;break;}temp = temp->next;//没通过判断就继续递增,直到等于indexcount++;}return head;
}//替换指定位置的元素
ListNode *replace(int index, int data, ListNode *head) {int count = 0;ListNode *cur = head;while (cur != NULL && count < index) {cur = cur->next;count++;}cur->data = data;return head;
}//通过下标删除元素
ListNode *cutByE(int index, ListNode *head) {int count = 0;if (head == NULL) {printf("链表为空,无法删除元素");}//删除头节点的情况if (index == 0) {ListNode *temp = head;head = head->next;free(temp);return head;}ListNode *prev = NULL;ListNode *cur = head;while (cur != NULL && count < index) {prev = cur;cur = cur->next;count++;}//执行删除操作prev->next = cur->next;free(cur);return head;
}//查找指定位置的元素
int getByi(int index, ListNode *head) {int count = 0;ListNode *temp = head;while (temp != NULL && count < index) {temp = temp->next;count++;}return temp->data;
}//查找指定元素的位置
int getByE(int data, ListNode *head) {ListNode *temp = head;int index = 0;while (data != temp->data && temp->next != NULL) {temp = temp->next;index++;}return index;
}//清空链表
void clean(ListNode *head) {ListNode *cur = head;while (cur->next != NULL) {ListNode *temp = cur;cur = cur->next;free(temp);}
}//推出程序
void esc() {printf("[999退出程序] 程序退出成功!");exit(0);
}//打印链表
void printList(ListNode *head) {ListNode *temp = head;if (head == NULL) {printf("\n链表为:[]");} else {printf("\n链表为:[");while (temp->next != NULL) {printf("%d->", temp->data);temp = temp->next;}printf("%d]\n", temp->data);}
}int main() {ListNode *head = NULL;while (1) {printf("功能编号列表:\n");printf("==101:在末尾添加元素\n");printf("==102:在指定位置添加元素\n");printf("==103:替换指定位置的元素\n");printf("==201:打印链表中的数据\n");printf("==301:删除元素\n");printf("==501:查找一个指定的位置的元素\n");printf("==502:查找一个指定的元素的位置\n");printf("==601:清空链表\n");printf("==999:退出程序\n");printf("请输入功能编号:\n");int cid;scanf("%d", &cid);if (cid == 101) {printf("[101添加元素]>>请输入一个数字:");int data;scanf("%d", &data);head = add(data, head);} else if (cid == 102) {printf("[102插入元素]>>请输入插入的位置和数据:");int index, data;scanf("%d %d", &index, &data);head = insert(index, data, head);} else if (cid == 103) {printf("[103替换元素]>>请输入替换的位置和新数据:");int index, data;scanf("%d %d", &index, &data);head = replace(index, data, head);} else if (cid == 501) {printf("[501查找指定位置的元素]>>请输入所需查找的位置:");int index;scanf("%d", &index);printf("该位置的元素为:");int data = getByi(index, head);printf("%d", data);} else if (cid == 502) {printf("[502查找指定元素的位置]>>请输入所需查找的元素:");int data;scanf("%d", &data);printf("该元素的位置为:");int place = getByE(data, head);printf("%d", place);} else if (cid == 601) {printf("[601清空链表]");clean(head);head = NULL;} else if (cid == 999) {esc();} else if (cid == 301) {int index;printf("[301删除元素]>>请输入所删除数据的下标:");scanf("%d", &index);head = cutByE(index, head);}printList(head);}return 0;
}

http://www.dtcms.com/a/458324.html

相关文章:

  • 2025-10-08 Python 标准库 5——内置类型:迭代器与序列类型
  • 网站常用模块做团购的家居网站有哪些
  • 网站建设最新教程视频家具网站案例
  • 深圳专业做公司网站网站后台发布了但看不见
  • 网站建设jw100个人视频网站应该怎么做
  • AFL(American Fuzzy Lop)
  • PTA6-6 使用函数判断完全平方数(C)
  • 找人做网站应该注意哪些浙江网站建设哪家专业
  • npm 扩展vite、element-plus 、windcss
  • 网站软件大全免费下如何架设网站服务器
  • 福州网站建设资讯网站维护推广怎么做
  • 电商网站报价网站建设意识形态
  • AI学习环境配置合集
  • C4D体积对象变量标签作为域:深度解析与应用指南
  • python 模拟鼠标键盘
  • 网页设计的网站房地产新闻最新消息
  • 自然语言处理实战——中文BERT模型可视化工具
  • 网站制作设及的技术网站设计初步规划
  • C# MVC网页调试的方法
  • Python自动化获取酷狗音乐
  • 自适应网站内容做多大尺寸织梦音乐网站
  • 怎么配置网站服务器电影片头在线制作网站
  • 【C语言基础】07. 字符串处理函数完全指南
  • 微信网站建设定制中国建设建行网站
  • Django REST Framework 全面指南:从模型到完整API接口开发
  • 建网站哪个公司好wordpress获取文章二级菜单
  • 德阳网站建设平台天津高端网站建设公司
  • Lookup | TryHackMe
  • Linux 端口管理完全指南:查询占用、检查开放与手动开放实操
  • 建站网站关键词优化动态的网站大概多少钱