【数据结构】单链表(二)

目录

1.查找数据

2.指定位置插入和删除节点

2.1 指定位置之前插入节点

2.2 指定位置之后插入节点

2.3 删除指定位置节点

2.4 删除指定位置之后的节点

3.销毁链表


我们接着上一篇【数据结构】单链表(一)-CSDN博客 来继续实现单链表

1.查找数据

SList.h中进行函数的声明

SLNode* SLfind(SLNode* pps, Type x);//查找

返回值是一个地址,如果找到,就返回这个数的地址,如果没找到,就返回NULL,参数就是链表首节点地址和要查找的数

SList.c中进行函数的实现

首先我们可以再定义一个指针存放首节点地址,这样的话在后面的遍历链表时就不会改变pps的指向了

SLNode* SLfind(SLNode* pps, Type x)//查找
{SLNode* pcur = pps;//新定义一个指针,指向首节点
}

然后就是循环遍历

SLNode* SLfind(SLNode* pps, Type x)//查找
{SLNode* pcur = pps;//新定义一个指针,指向首节点while (pcur)//pcur不能为空{if (pcur->data == x) //找到return pcur;//直接返回地址pcur = pcur->next;//没找到往后找}
}

当跳出while循环时,证明没找到,此时pcur为空,我们直接返回NULL

SLNode* SLfind(SLNode* pps, Type x)//查找
{SLNode* pcur = pps;//新定义一个指针,指向首节点while (pcur)//pcur不能为空{if (pcur->data == x) //找到return pcur;//直接返回地址pcur = pcur->next;//没找到往后找}return NULL;//没找到
}

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLNode* find = SLfind(plist, 2);if (find == NULL)printf("没找到\n");elseprintf("找到了\n");
}
int main()
{//SListtest1();//SListtest2();SListtest3();return 0;
}

 自己测试的时候可以多测几次

2.指定位置插入和删除节点

上一篇我们说了头部尾部的插入和删除数据,现在我们来实现一下指定位置的插入和删除数据

2.1 指定位置之前插入节点

SList.h中进行函数的声明

void SLInsert(SLNode** pps, SLNode* pos, Type x);//指定之前插

参数有三个:链表首节点的地址,指定的位置,要插入的数据

SList.c中进行函数的实现

 现在我们要在节点3前面插入一个节点,就要让节点2里面的next指向新节点,新节点里面的next指向节点3

我们先找pos的前一个结点 ,用循环遍历

void SLInsert(SLNode** pps, SLNode* pos, Type x)//指定之前插
{assert(pps && *pps);assert(pos);SLNode* prev = *pps;//再定义一个指针变量初始指向首节点while (prev->next != pos){prev = prev->next;}
}

跳出循环后此时prev指向pos前一个节点,然后让这些节点“手牵手”

void SLInsert(SLNode** pps, SLNode* pos, Type x)//指定之前插
{assert(pps && *pps);assert(pos);SLNode* newnode = SLBuyNode(x);//插入的数据SLNode* prev = *pps;//再定义一个指针变量初始指向首节点while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;
}

代码写到这里我们在分析一下pos为1时可不可行

 这种情况下prev会一直往后走,直到走到最后一个节点,上面的代码在次情况下行不通

我们再分析一下pos为最后一个节点时可不可行

依旧是让节点3里面的next指向新节点,新节点里面的next指向节点4

经分析,上面的代码在这种情况下可行,所以不可行的就是pos为1的情况,我们单独把这种情况列出来,其实pos为1时也就是头插的情况

void SLInsert(SLNode** pps, SLNode* pos, Type x)//指定之前插
{assert(pps && *pps);assert(pos);SLNode* newnode = SLBuyNode(x);//插入的数据if (pos == *pps){SLPushHead(pps, x);//直接调用头插代码}else//其他位置{SLNode* prev = *pps;//再定义一个指针变量初始指向首节点while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}

这就是完整的代码

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLNode* find = SLfind(plist, 2);//找2SLInsert(&plist, find, 11);//直接插在2前面SLPrint(plist);//打印
}
int main()
{SListtest3();return 0;
}

看结果

其他情况有疑惑的话一定要自己测试运行一下

2.2 指定位置之后插入节点

SList.h中进行函数的声明

void SLAfter(SLNode* pos, Type x);//指定之后插

这里只有两个参数,一个是指定位置,一个是要插入的值,这里我们不需要知道头节点,因为可以通过pos找到下一个节点,在指定位置之前插入数据的函数需要头节点是因为我们不能通过pos找到pos的前一个节点

SList.c中进行函数的实现

void SLAfter(SLNode* pos, Type x)//指定之后插
{assert(pos);SLNode* newnode = SLBuyNode(x);//插入的数据newnode->next = pos->next;pos->next = newnode;
}

注意:  newnode->next = pos->next;   pos->next = newnode;这两句代码的顺序不可以交换,交换后是错的

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLNode* find = SLfind(plist, 2);//找2SLInsert(&plist, find, 11);//直接插在2前面SLPrint(plist);//打印SLAfter(find, 5);//插在2后面SLPrint(plist);//打印
}
int main()
{SListtest3();return 0;
}

代码没有问题

2.3 删除指定位置节点

SList.h中进行函数的声明

void SLErase(SLNode** pps, SLNode* pos);//删除pos节点

参数是二级指针,接收首节点地址,还有一个参数是要删除的节点

SList.c中进行函数的实现

我们要让pos的前一个节点指向pos的后一个节点,然后把pos这个节点销毁

既然要找pos的前一个节点,我们依旧是定义一个指针prev,初始为*pps,往后一个一个找,直到找到pos前一个节点 

void SLErase(SLNode** pps, SLNode* pos)//删除pos节点
{assert(pps && *pps);assert(pos);SLNode* prev = *pps;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;
}

如果此时链表只有一个节点,上面的代码可行吗?来分析一下

发现代码走不通,其实这种情况就是头删的情况,我们直接调用头删的代码就可以了

void SLErase(SLNode** pps, SLNode* pos)//删除pos节点
{assert(pps && *pps);assert(pos);if (pos == *pps)//一个节点{SLPopHead(pps);}else//多个节点{SLNode* prev = *pps;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLNode* find = SLfind(plist, 7);//找7SLErase(&plist, find);//删除指定位置节点SLPrint(plist);//打印
}
int main()
{SListtest3();return 0;
}

删除成功

2.4 删除指定位置之后的节点

SList.h中进行函数的声明

void SLPushAfter(SLNode* pos);//删除pos之后的节点

pos的后一个节点我们可以直接通过pos找到,就不需要头节点地址,所以一个参数就好了

 在SList.c中进行函数的实现

 

还是先让pos这个节点找到它的下下个节点,然后再销毁pos后面的节点

 这里呢我们需要一个临时变量存放pos->next的地址,然后再连接节点

 我们先写一下代码,让pos和pos下下个节点相连

void SLPushAfter(SLNode* pos)//删除pos之后的节点
{assert(pos);assert(pos->next);SLNode* temp = pos->next;pos->next = temp->next;
}

 然后销毁pos下一个节点并置空

void SLPushAfter(SLNode* pos)//删除pos之后的节点
{assert(pos);assert(pos->next);SLNode* temp = pos->next;//临时变量pos->next = temp->next;//连接free(temp);//销毁temp = NULL;//置空
}

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLNode* find = SLfind(plist, 7);//找7SLPushAfter(find);//删除指定位置后一个节点SLPrint(plist);//打印
}
int main()
{SListtest3();return 0;
}

3.销毁链表

跟顺序表一样,链表使用完之后也要销毁,链表由一个一个节点组成,所以也要一个一个销毁

SList.h中进行函数的声明

void SLDestroy(SLNode** pps);//销毁

参数就是首节点地址

SList.c中进行函数的实现

我们在销毁当前节点之前要把下一个节点的信息存起来

 销毁空间

pcur后移到提前保存的next处

 

然后next后移,把当前的pcur销毁

就这样一直往后,直到pcur为空

代码来实现一下


void SLDestroy(SLNode** pps)//销毁
{assert(*pps && pps);SLNode* pcur = *pps;while (pcur){SLNode* next = pcur->next;//存下节点信息free(pcur);//释放pcur = next;//往后走}*pps = NULL;//不要忘了头节点此时没有置空,要置空
}

test.c中测试一下

void SListtest3()
{SLNode* plist = NULL;//空链表SLPushBack(&plist, 1);//尾插SLPushBack(&plist, 2);SLPushHead(&plist, 6);//头插SLPushHead(&plist, 7);SLPrint(plist);//打印SLDestroy(&plist);//销毁SLPrint(plist);//打印
}
int main()
{SListtest3();return 0;
}

可以自己通过调试看结果,能看到更详细,打印出来看也可以

单链表实现就分享到这里,拜拜~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/810443.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2. 如何让mybatis-plus的逻辑删除注解@TableLogic临时失效

文章目录 如何让mybatis-plus的逻辑删除注解TableLogic临时失效1. 场景复现1.1 controller代码1.2 service层代码1.3 entity代码 2. 问题分析3. 解决方案3.1 说明3.2 核心代码3.3 service方法对应修改为3.4 运行结果 如何让mybatis-plus的逻辑删除注解TableLogic临时失效 1. 场…

【QT教程】QT6 QML界面布局艺术

QT6 QML界面布局艺术 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看…

7、configMap

1、configMap是什么 类似与pod的配置中心,不会因为pod的创建销毁,相关配置发生改变 pod定义硬编码意味着需要有效区分⽣产环境与开发过程中的pod 定义。为了能在多个环境下复⽤pod的定义,需要将配置从pod定义描 述中解耦出来。 2、向容器中…

Mongodb入门--头歌实验MongoDB 文档的高级查询操作

数据库存储了大量的数据&#xff0c;当我们需要特定的数据时就要使用查询方法&#xff0c;根据一定的条件&#xff0c;筛选出我们想要的数据&#xff0c;前一章我们简单介绍了条件操作符&#xff08;<、<、>、>、!等&#xff09;&#xff0c;在这一章中我们将更全面…

重生奇迹MU弓箭手装备介绍

重生奇迹MU弓箭手装备搭配什么好呢&#xff1f;装备的搭配对于角色来说帮助很大&#xff0c;所以我们更加要选择合适的装备来搭配。 装备打造 ①装备强化&#xff1a;装备强化需要强化材料 灵魂宝石、祝福宝石、玛雅宝石&#xff0c;强化有几率失败&#xff0c;失败不会导致…

贪心算法|968.监控二叉树

力扣题目链接 class Solution { private:int result;int traversal(TreeNode* cur) {// 空节点&#xff0c;该节点有覆盖if (cur NULL) return 2;int left traversal(cur->left); // 左int right traversal(cur->right); // 右// 情况1// 左右节点都有覆盖if (le…

MM-Grounding-DINO的训练推理(待更新)

1、简单介绍 继前面发布的 GroundingDino 和 Open-GroundingDino的推理 和 Open-GroundingDino的训练实现&#xff0c;作为 GroundingDino延续性的文本检测网络 MM-Grounding-DINO 也发布了较详细的 训练和推理实现教程&#xff0c;而且操作性很强。作为学习内容&#xff0c;也…

IO流【内存流、打印流、随机访问流】;初识网络编程

day37 IO流 继day36 各种流 对象流 day36 内存流 class ByteArrayInputStream – 内存输入流 class ByteArrayOutputStream – 内存输出流 注意&#xff1a; 内存流是程序和内存交互&#xff0c;跟文件无关内存流是程序到内存的通道&#xff0c;是关闭不掉的 应用场景&#x…

深度学习pytorch好用网站分享

深度学习在线实验室Featurizehttps://featurize.cn/而且这个网站里面还有一些学习教程 免费好用 如何使用 PyTorch 进行图像分类https://featurize.cn/notebooks/5a36fa40-490e-4664-bf98-aa5ad7b2fc2f 华为modelArtshttps://bbs.huaweicloud.com/forum/thread-76328-1-1.html…

阿里云飞燕平台搭建与linux程序通信(全图文教程)

阿里云飞燕平台搭建与linux程序通信&#xff08;全图文教程&#xff09; 一、MQTT理论1.1 概念1.2 理解发布和订阅1.3 MQTT传输的消息组成 二、阿里云飞燕平台搭建2.1 产品创建2.2 自定义自己的功能2.3 人机交互 三、测试3.1代码分析3.2 效果验证 一、MQTT理论 1.1 概念 MQTT…

flutter组件_AlertDialog

官方说明&#xff1a;A Material Design alert dialog. 翻译&#xff1a;一个材料设计警告对话框。 作者释义&#xff1a;显示弹窗&#xff0c;类似于element ui中的Dialog组件。 AlertDialog的定义 const AlertDialog({super.key,this.icon,this.iconPadding,this.iconColor,t…

边缘计算平台原理、关键功能以及技术优势

1、什么是边缘计算及其工作原理&#xff1f; 边缘计算是一种分布式计算模型&#xff0c;它将数据处理和存储靠近数据源头和最终用户的边缘设备上&#xff0c;从而减少了数据传输和延迟。边缘计算旨在解决云计算模型所面临的问题&#xff0c;例如延迟高、带宽瓶颈和安全性等问题…

【JavaWeb】Day38.MySQL概述——数据库设计-DQL(一)

数据库设计——DQL 介绍 DQL英文全称是Data Query Language(数据查询语言)&#xff0c;用来查询数据库表中的记录。 查询关键字&#xff1a;SELECT 查询操作是所有SQL语句当中最为常见&#xff0c;也是最为重要的操作。在一个正常的业务系统中&#xff0c;查询操作的使用频次…

Python实现BOA蝴蝶优化算法优化随机森林分类模型(RandomForestClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝴蝶优化算法(butterfly optimization algorithm, BOA)是Arora 等人于2019年提出的一种元启发式智能算…

cmake + mingw32构建和编译第三方lib库, qt 使用lib库

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 背景 qt 有两种编译器&#xff0c;分别是visual studio和MinGW。很多第三方库提供编译好的visual studio 库&#xff0c;MinGW库需要自己编译。喜欢MinGW没有太多版本…

vs2022启动cmake项目(qt+c++)

1.本工程&#xff0c;如图&#xff0c;1个cmakelist.txt3个文件 2.启动vs 3.选择文件夹 4.进入这个页面&#xff0c;就说明配置没问题 5.启动 6.最后会自己生成其他文件

Proteus 8 的使用记录

创建仿真文件 新建文件&#xff1a;默认下一步&#xff0c;至完成创建。 功能选择如图&#xff1a; 放置器件 常用元器件名称 keywords 常用51单片机 AT89C52 晶振 CRYSTAL 电阻 RES 排阻 RESPACK-8 瓷片电容 CAP 电解电容 CAP-ELEC 单刀单掷开关 S…

网络协议学习——以太网协议

目录 ​编辑 一&#xff0c;以太网简介 二&#xff0c;以太网通信的过程 为什么不用IP地址&#xff1f; 过程 MAC帧 MAC帧的字段介绍 ARP协议 传输过程的一些问题 RARP协议 提高效率 三&#xff0c;其他问题 ARP诈骗问题 URL解析过程 一&#xff0c;以太网简介 …

python图书馆图书借阅系统含网上商城管理系统7d538

&#xff0c;python语言&#xff0c;django框架进行开发&#xff0c;后台使用MySQL数据库进行信息管理&#xff0c;设计开发的图书管理系统。通过调研和分析&#xff0c;系统拥有管理员和用户两个角色&#xff0c;主要具备注册登录、个人信息修改、用户、图书分类、图书信息、借…

Django交易商场

Hello&#xff0c;我是小恒不会java 最近学习django&#xff0c;写了一个demo,学到了不少东西。 我在GitHub上开源了&#xff0c;提示‘自行查看代码&#xff0c;维护&#xff0c;运行’。 最近有事&#xff0c;先发布代码了&#xff0c;我就随缘维护更新吧 介绍&#xff1a; 定…