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

92.【C语言】数据结构之单向链表的查找,中间插入和删除,销毁

目录

1.链表的查找函数

2.链表的修改函数

3.链表的中间插入函数

1.在pos之前插入:SLTInsertBefore函数

1.借助头指针pphead

示意图

代码示例(写入SList.c)

头文件添加SLTInsertbefore的声明

main.c的部分代码改为

1.测试中间插入

2.测试头部插入

3.测试pos为NULL的情况

2.不借助头指针pphead

代码示例

2.在pos之后插入:SLTInsertAfter函数

代码示例

错误写法

4.链表的中间删除函数

示意图(非头删)

1.在pos之前删除:SLTEraseBefore函数

1.借助头指针pphead

代码示例

头文件添加SLTErase的声明

main.c的部分代码改为

运行结果

2.不借助头指针pphead

示意图

代码示例

2.在pos之后删除:SLTEraseBeforeAfter函数

代码示例

4.链表的销毁函数

代码示例(写入SList.c)

main.c部分代码改为

运行结果

错误写法

VS2022+debug+x86环境下调试错误代码


承接91.【C语言】数据结构之链表的头删和尾删文章

这里均以单向链表做演示

1.链表的查找函数

代码示例(遍历查找)

void SLTFind(SLTNode* phead, SLTDataType find)
{SLTNode* cur = phead;//初始化cur指针while (cur){if (cur->data == find){return cur;}//找不到则将下一个节点的地址赋值给curcur = cur->next;}//从头找到尾没找到,则返回NULLreturn NULL;
}

2.链表的修改函数

有了查找函数,就可以轻松实现修改函数

修改函数的策略:先查某个节点的数据,再对这个数据进行修改

代码示例(写入SList.c)

void SLTMod(SLTNode* phead, SLTDataType find, SLTDataType mod)
{//将需要修改数据的节点的地址赋值给tar_p//tar_p为目标指针(target_pointer)SLTNode* tar_p = SLTFind(phead, find);//修改目标节点的数据tar_p->data = mod;
}

main.c部分代码改为

void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist);SLTFind(plist, 3);SLTMod(plist, 3, 5);SLTPrint(plist);
}

执行结果

3.链表的中间插入函数

插入包括:在pos之前插入和在pos之后插入

1.在pos之前插入:SLTInsertBefore函数

1.借助头指针pphead

示意图

在pos之前插入,要找pos前的节点,需要参数SLTNode* phead

代码示例(写入SList.c)
void SLTInsertBefore(SLTNode** pphead, SLTNode* pos,SLTDataType x)
{//判断pos是否为NULLassert(pos);//pphead不能为NULLassert(pphead);//判断pos是否为头指针,如果是则调用现有的函数if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//初始化新节点SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}

注意:

1.一开始就要判断判断pos是否为NULL

2.将pos分是否为头指针两种情况讨论

如果不判断pos是否为头指针,直接硬插入的话,会报错

分析原因:当pos为头指针时,pos和prev指针存储的内容是一样的,第一次循环条件prev->next!=pos成立,错过了prev->next==pos的机会,则while会一直循环,直到prev为NULL(x86下存储的00 00 00 00),出现NULL->next是不合法的,因此报错

3.pphead不能为NULL(即plist存储的地址不能为NULL),plist可以为NULL(空链表)

头文件添加SLTInsertbefore的声明
main.c的部分代码改为
1.测试中间插入
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist);SLTNode* pos = SLTFind(plist, 3);SLTInsertBefore(&plist, pos, 5);SLTPrint(plist);
}

2.测试头部插入
SLTNode* pos = SLTFind(plist, 1);

 

3.测试pos为NULL的情况

均可以实现

2.不借助头指针pphead

只需要交换即可

代码示例
void SLTInsertBefore(SLTNode** pos, SLTDataType x)
{SLTNode* newnode = BuySLTNode(x);//用中间变量n_tmp(全称next_tmp)交换SLTDataType tmp = (*pos)->data;(*pos)->data = newnode->data;newnode->data = tmp;//找pos的下一个节点,暂存到n_tmpSLTNode* n_tmp = (*pos)->next;//变动指针(*pos)->next = newnode;newnode->next = n_tmp;
}

 头插和尾插均可

2.在pos之后插入:SLTInsertAfter函数

代码示例
void SLTInsertAfter(SLTNode* pos,SLTDataType x)
{assert(pos);//pos不可为NULLSLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}

错误写法

void SLTInsertAfter(SLTNode* pos,SLTDataType x)
{assert(pos);//pos不可为NULLSLTNode* newnode = BuySLTNode(x);pos->next = newnode;newnode->next = pos->next;
}

反过来写会出问题,比如想在d2节点后插入新节点

这样做是无效

4.链表的中间删除函数

示意图(非头删)

1.在pos之前删除:SLTEraseBefore函数

1.借助头指针pphead

代码示例
void  SLTEraseBefore(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{//找pos的前一个SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}

注意:

1.断言pphead,*pphead(即plist)和pos

2.头删直接调用SLTPopFront函数

3.不采取pos = NULL;,SLTErase中的pos为形参,没有办法真正为删除的节点含有的指针置NULL,应该在main.c中操作

头文件添加SLTErase的声明
main.c的部分代码改为
void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist);SLTNode* pos = SLTFind(plist, 3);SLTEraseBefore(&plist,pos);pos = NULL;SLTPrint(plist);
}

注意pos = NULL;

运行结果

2.不借助头指针pphead

示意图

代码示例
void  SLTEraseBefore(SLTNode** pos)
{assert((*pos)->next);(*pos)->data = ((*pos)->next)->data;(*pos)->next = ((*pos)->next)->next;
}
//或写成下面这样
void  SLTEraseBefore(SLTNode* pos)
{assert(pos->next);pos->data = (pos->next)->data;pos->next = (pos->next)->next;
}

注意:此方法有缺陷,不能尾删,因此断言

2.在pos之后删除:SLTEraseBeforeAfter函数

代码示例
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//不为空链表assert(pos->next);//不为末尾节点SLTNode* delete = pos->next;//也可以写成pos->next = delete->next;pos->next = (pos->next)->next;free(delete);delete = NULL;
}

注意:不可以不写SLTNode* delete = pos->next;,一旦pos->next被修改后,要删除的节点的指针会丢失,因此要先用结构体指针delete保存

4.链表的销毁函数

代码示例(写入SList.c)

采用双指针法

void SLTDestory(SLTNode* phead)
{SLTNode* p1 = phead;while (p1){SLTNode* p2 = p1->next;free(p1);p1 = p2;}
}

注:

1.p1相当于慢指针,p2相当于快指针

2.一定先保存p1->next才能free(p1);防止p1->next值被操作系统修改从而找不到下一个节点的地址!

main.c部分代码改为

void TestSList1()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist);SLTDestory(plist);plist = NULL;//不能在SLTDestory内置NULL,形参的改变不影响实参
}

注:如果不想在main.c中手动为plist置空,可以修改SLTDestory(&plist);

void SLTDestory(SLTNode** pphead)
{assert(pphead);SLTNode* p1 = *pphead;while (p1){SLTNode* p2 = p1->next;free(p1);p1 = p2;}*pphead = NULL;
}

运行结果

错误写法

void SLTDestory(SLTNode* phead)
{SLTNode* p1 = phead;while (p1){SLTNode* p2 = p1;free(p1);p1 = p2->next;}
}

对free的本质认识不清楚,free函数是将指针所指向的内存空间的使用权交还给操作系统,操作系统会改变内存空间的值,并没有改变指针的值,因此p2->next会变成野指针

VS2022+debug+x86环境下调试错误代码

SLTNode* p2 = p1;执行后

free(p1);执行后

p1->next被操作系统修改成0xdddddddd,p1->next为野指针

第二次执行完SLTNode* p2 = p1;后

显然再次执行free(p1);肯定会报错,访问冲突,无权限修改内存

相关文章:

92.【C语言】数据结构之单向链表的查找,中间插入和删除,销毁

目录 1.链表的查找函数 2.链表的修改函数 3.链表的中间插入函数 1.在pos之前插入:SLTInsertBefore函数 1.借助头指针pphead 示意图 代码示例(写入SList.c) 头文件添加SLTInsertbefore的声明 main.c的部分代码改为 1.测试中间插入 2.测试头部插入 3.测试pos为NULL的…...

WPF+MVVM案例实战(七)- 系统初始化界面字体描边效果实现

文章目录 1、案例效果展示2、项目准备3、功能实现1、资源获取2、界面代码3、后台代码4 源代码获取1、案例效果展示 2、项目准备 打开项目 Wpf_Examples,新建系统初始化界面 WelcomeWindow.xmal,如下所示: 3、功能实现 1、资源获取 案例中使用的CSDN文字为路径文字,从字体…...

基于 C# 的 AI 算法测试方法

基于 C# 的 AI 算法测试方法 在当今人工智能蓬勃发展的时代,AI 算法的质量和可靠性至关重要。对于使用 C# 开发的 AI 算法,我们需要一套有效的测试方法来确保其性能、准确性和稳定性。本文将详细探讨基于 C# 的 AI 算法测试方法,帮助开发者更…...

Find My画框|苹果Find My技术与画框结合,智能防丢,全球定位

画框通常用于保护和固定艺术品,尤其是绘画作品。它是一种可以展示艺术品的框架,用于保护艺术品免受损坏或污染。艺术品被放置在画框内,可以避免受到空气、尘土和其他外部因素的损害。同时,画框还可以增强艺术品的展示效果&#xf…...

布谷语音源码服务器搭建环境及配置流程

布谷语音源码部署环境安装要求(只有在相同的环境下才更容易避免一些不必要的麻烦):●安装Center OS 7.9,我们自己的服务器使用的是7.9建议相同系统,非强制●安装宝塔环境(强烈推荐使用)●安装软…...

算法|牛客网华为机试21-30C++

牛客网华为机试 上篇:算法|牛客网华为机试10-20C 文章目录 HJ21 简单密码HJ22 汽水瓶HJ23 删除字符串中出现次数最少的字符HJ24 合唱队HJ25 数据分类处理HJ26 字符串排序HJ27 查找兄弟单词HJ28 素数伴侣HJ29 字符串加解密HJ30 字符串合并处理 HJ21 简单密码 题目描…...

Tomcat servlet response关于中文乱码的经验

前言 最近修改老项目项目,使用zuul网关返回的中文内容乱码了,如果使用GBK或者GB2312编码确正常显示,稍微实验了一下,发现里面很多细节,毕竟Springboot对我们做了很多事情,而且当我们使用不同的模式会出现很…...

WebGIS开发丨从入门到进阶,全系列课程分享

WebGIS开发所需的技能 1.前端技能:Html、CSS、 Javascript、WebAPLs、Vue 2.二维技能:WebGIS基础理论及开发、MapGIS二次开发Openlayers、Leaflet、Mapbox 、Echarts、公共开发平台开发等 3.三维技能:Blender、Three.js、Cesium等 Web开发…...

C++ 模板专题 - 标签分派(Tag Dispatching)

一:概述: 在 C 中,Tag Dispatching 是一种编程技巧,主要用于在编译期根据不同的类型或特征选择不同的函数重载或代码分支。Tag Dispatching 借助类型标签(tags)进行函数调度,用于在模板中实现编译期的静态分…...

如何解决RabbitMQ消息的重复消费问题

什么情况下会导致消息的重复消费——在消费者还没成功发送自动确认机制时发生: 网络抖动消费者挂了 解决方案 每条消息设置一个唯一的标识id幂等方案:【Redis分布式锁、数据库锁(悲观锁、乐观锁)】 面试官:如何解决…...

Java调用chatgpt

目前openai的chatgpt在国内使用有一定难度,不过国内的大模型在大部分情况下已经不弱于chatgpt,而且还更便宜,又能解决国内最敏感的内容安全问题。本文后续以spring ai调用国内chatgpt厂商实现为例,讲解怎么构建一个java调用chatgp…...

将你的 Kibana Dev Console 请求导出到 Python 和 JavaScript 代码

作者:来自 Elastic Miguel Grinberg Kibana Dev Console 现在提供将请求导出到可立即集成到你的应用程序中的 Python 和 JavaScript 代码的选项。 你使用过 Kibana 开发控制台吗?这是一个非常棒的原型设计工具,可让你以交互方式构建和测试 El…...

成都世运会志愿者招募报名流程及证件照制作方法

成都世运会志愿者招募正在如火如荼地进行中,许多热心公益的青年们纷纷报名参与。本文将详细介绍如何通过官方渠道报名,并使用手机来自行制作符合要求的4:5比例的白底证件照。 一、志愿者报名流程概述首先,报名成都世运会志愿者需要通过官方指…...

大数据技术的前景如何?

在当今数字化迅猛发展的时代,大数据技术的前景显得尤为广阔。随着数据量的激增,如何有效利用这些数据成为了各行各业关注的焦点。未来五年,大数据技术的发展趋势可以从市场规模、技术融合、行业应用和政策支持等多个方面进行深入分析。 1. 市…...

LLM | 论文精读 | 基于大型语言模型的自主代理综述

论文标题:A Survey on Large Language Model based Autonomous Agents 作者:Lei Wang, Chen Ma, Xueyang Feng, 等 期刊:Frontiers of Computer Science, 2024 DOI:10.1007/s11704-024-40231-1 一、引言 自主代理(…...

详解Redis相关缓存问题

目录 缓存更新策略 定期⽣成 实时⽣成 缓存淘汰策略 Redis内置缓存淘汰策略 缓存预热 缓存穿透 缓存雪崩 缓存击穿 缓存更新策略 定期⽣成 每隔⼀定的周期(⽐如⼀天/⼀周/⼀个⽉), 对于访问的数据频次进⾏统计. 挑选出访问频次最⾼的前 %N的数据. 实时⽣成 先给缓存…...

ubuntu 24 (wayland)如何实现无显示器远程桌面

ubuntu 24默认采用的是wayland而非x11,查过文档vnc对wayland的支持不是很好,折腾了好久,弄了一个如下的方案供参考: 硬件条件 需要一个显卡欺骗器或者可以接HDMI口作为视频信号源输出的设备。 将ubuntu的主机的HDMI输出接到该硬…...

《模拟电子技术基础》第六版PDF课后题答案详解

《模拟电子技术基础》第六版是在获首届全国优秀教材建设奖一等奖的第五版的基础上,总结6年来的教学实践经验修订而成的新形态教材。为满足国家人才培养的需求,适应新型教学模式,并考虑到大多数院校逐渐减少课程学时的现状,在不降低…...

python知识收集

文章目录 语法def声明函数class声明类class 子类(父类) 继承 数据结构列表列表操作 元组元组操作 字典遍历字典 集合 文件读写读文件写文件 csv模块读入写入 time模块发送邮件制作二维码滚动广告 语法 def声明函数 class声明类 class 子类(父类) 继承 数据结构 列表 列表…...

传奇996_3——使用补丁添加怪物

找素材,看素材是否是打包好的,没有的话就使用工具进行素材打包(打包好后尽量别改名),并复制进客户端,D:\chuanqinew\996M2_debug\dev\anim\monster找到模型表cfg_model_info.xls,复制表中前几行…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

Cursor实现用excel数据填充word模版的方法

cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层&#xf…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...