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技术与画框结合,智能防丢,全球定位
画框通常用于保护和固定艺术品,尤其是绘画作品。它是一种可以展示艺术品的框架,用于保护艺术品免受损坏或污染。艺术品被放置在画框内,可以避免受到空气、尘土和其他外部因素的损害。同时,画框还可以增强艺术品的展示效果…...
布谷语音源码服务器搭建环境及配置流程
布谷语音源码部署环境安装要求(只有在相同的环境下才更容易避免一些不必要的麻烦):●安装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,复制表中前几行…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
