单链表专题(中)
我们接着上一篇文章,继续对单链表的实现进行扩充
链表的头删
我们在进行头删的时候,不能先释放掉头节点再将头节点传到第二节点上,这样会导致找不到第二个节点了
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead); //链表不能为空SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}
链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//此时 pcur == NULLreturn NULL;
}
我们注意看一下只有一个节点的情况:
只有一个节点的时候,此时 next = NULL, *pphead = NULL,符合一个节点头删后变成空链表的情况,所以该代码适用于所有情况。
在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);}
这里的 pos 为链表中的某个指定的位置
这里请注意 *pphead 不能为空,因为如果 *pphead 为空了,那 pos 肯定也为空,我们是无法在空指针前面插入数据的,所以断言一下
所以我们的思路是:
- 根据 pos 节点找到前一个节点和后一个节点
- 创建一个新的节点
- 将三者依次相连
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = SLTBuyNode(x);newnode->next = pos;prev->next = newnode;
}
特殊情况: 当 pos 节点为首节点时,prev 节点是找不到的,导致在循环中遍历到结束后跳出该链表造成空指针的解引用,程序报错。所以该情况要特别讨论,即头插
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* newnode = SLTBuyNode(x);if (pos == *pphead){SLTPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}
在指定的位置之后插入数据
先看函数的定义:
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
这个函数只需要两个参数而不需要头节点的地址。原因是我们是在指定位置之后插入数据,而关于链表的查找节点是单向的,只能从前一个节点往后一个节点遍历,不可回溯。
我们思考一个问题,将 pos 节点 newnode 节点 pos->next 节点连接起来的顺序是什么样的?
显然,如果我们先将 pos 节点和 newnode 节点相连,则 pos->next == newnode ,再将 newnode 和 pos->next相连,即 newnode->next == pos->next ,很容易发现问题,pos->next 节点已经被换了所以这样的顺序并不成立。正确的做法是 newnode 节点先和 pos->next 节点相连,再将 pos 节点和 newnode 节点相连。
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}
删除pos节点
思路如下:
- 找到 pos 节点的前一个节点 prev
- 将前一个节点与 pos 节点的后一个节点相连
- 释放 pos 节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(*pphead && pphead);assert(pos);SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;
}
同样的问题,假设链表要释放的是头节点的时候,此时 prev 节点无法找到导致出现对空指针解引用的错误报错。所以要分情况讨论
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(*pphead && pphead);assert(pos);if (pos == *pphead){//与头删代码一致SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}
删除pos之后的节点
思路很简单:
- 找到 pos 的下一个节点 pos->next 和下一个节点的下一个节点 pos->next->next
- 将pos 节点和下下个节点相连
- 释放掉下一个节点 pos->next
我们先上代码:
void SLTErase(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
为什么这里我们定义了临时变量 del 去储存 pos->next 呢?
看回之前的思路,我们如果将 pos 节点和下下个节点相连,即 pos->next = pos->next->next 后,再释放 pos->next 节点,我们释放的不再是 pos 节点的下一个节点而是下下个节点了,顺序乱了。所以创建临时变量去储存 pos->next 隔离开关系即可
链表的销毁
因为我们的链表是动态生成的,所以用完了要及时销毁
链表是一个一个生成的,所以销毁也是一个一个销毁
我i们不能一上来就把头节点销毁了,这样如何找到下一个节点呢?所以,我们先储存后一个节点,在删除前一个节点,这样依次往后走,直到所有节点都被销毁
void SListDestroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}
至此,单链表的实现就全部结束了 !
相关文章:
单链表专题(中)
我们接着上一篇文章,继续对单链表的实现进行扩充 链表的头删 我们在进行头删的时候,不能先释放掉头节点再将头节点传到第二节点上,这样会导致找不到第二个节点了 void SLTPopFront(SLTNode** pphead) {assert(pphead && *pphead);…...
表格结构标签
<!-- thead表示表格的头部 tbody表示表格的主体 --> <thead></thead> <tbody></tbody> <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content&q…...
A星算法两元障碍物矩阵转化为rrt算法四元障碍物矩阵
对于a星算法obstacle所表示的障碍物障碍物信息,每行表示一个障碍物的坐标,例如2 , 3; % 第一个障碍物在第二行第三列,也就是边长为1的正方形障碍物右上角横坐标是2,纵坐标为3,障碍物的宽度和高度始终为1.在rrt路径规划…...
MySQL数据库(二)- SQL
目录 编辑 一 DDL (一 数据库操作 1 查询-数据库(所有/当前) 2 创建-数据库 3 删除-数据库 4 使用-数据库 (二 表操作 1 创建-表结构 2 查询-所有表结构名称 3 查询-表结构内容 4 查询-建表语句 5 添加-字段名数据类型 6 修改-字段数据类…...
数据分析系列--⑦RapidMiner模型评价(基于泰坦尼克号案例含数据集)
一、前提 二、模型评估 1.改造⑥ 2.Cross Validation算子说明 2.1Cross Validation 的作用 2.1.1 模型评估 2.1.2 减少过拟合 2.1.3 数据利用 2.2 Cross Validation 的工作原理 2.2.1 数据分割 2.2.2 迭代训练与测试 2.2.3 结果汇总 …...
19 压测和常用的接口优化方案
高并发的平台应用,项目上线前离不开一个重要步骤就是压测,压测对于编码中的资源是否问题的排查,性能的调优都是离不开的。测试还要做测试报告,出具了测试报告给到运维团队才能上线。 压测的测试报告主要有以下几个方面:1.响应时间…...
gentoo中利用ollama运行DeepSeek-R1
一、安装ollama gentoo linux中 1.安装步骤: Step1. #cd /usr/local/src Step2. #wget2 -o -V https://ollama.com/install.sh Setp3. #sh ./install.sh 2.ollama完成安装。查看ollama版本: 3.查看ollama服务运行状态: 二、安装…...
远程连接-简化登录
vscode通过ssh连接远程服务器免密登录(图文)_vscode ssh-CSDN博客...
PHP中配置 variables_order详解
variables_order 是 PHP 配置文件 php.ini 中的一项配置指令,决定了 PHP 在处理请求时,哪些类型的变量将被注册到全局变量空间(如 $GLOBALS)中,以及这些变量的顺序。理解和正确配置 variables_order 对于开发和维护安全…...
为什么推荐将静态资源放在CDN上?
1. CDN 是什么? CDN(Content Delivery Network)是一种分布式网络,由地理上分散的服务器节点组成。其主要功能是将静态资源缓存到各地的边缘服务器上,从而将内容更快地传递给用户。当用户请求资源时,CDN 会…...
【NEXT】网络编程——上传文件(不限于jpg/png/pdf/txt/doc等),或请求参数值是file类型时,调用在线服务接口
最近在使用华为AI平台ModelArts训练自己的图像识别模型,并部署了在线服务接口。供给客户端(如:鸿蒙APP/元服务)调用。 import核心能力: import { http } from kit.NetworkKit; import { fileIo } from kit.CoreFileK…...
工作总结:压测篇
前言 压测是测试需要会的一项技能,作为开发,有点时候也要会一点压测。也是被逼着现学现卖的。 一、压测是什么,以及压测工具的选择 压测,即压力测试,是一种性能测试手段,通过模拟大量用户同时访问系统&am…...
MySQL基本架构SQL语句在数据库框架中的执行流程数据库的三范式
MySQL基本架构图: MySQL主要分为Server层和存储引擎层 Server层: 连接器:连接客户端,获取权限,管理连接 查询缓存(可选):在执行查询语句之前会先到查询缓存中查看是否执行过这条语…...
CSS 中调整元素大小的全面指南
CSS 中调整元素大小的全面指南 1. 原始尺寸(固有尺寸)示例代码:图像的固有尺寸 2. 设置具体的尺寸示例代码:设置固定宽度和高度 3. 使用百分比示例代码:使用百分比设置宽度 4. 使用百分比作为外边距和内边距示例代码&a…...
Hive存储系统全面测试报告
引言 在大数据时代,数据存储和处理技术的重要性日益凸显。Apache Hive作为一个基于Hadoop的数据仓库工具,因其能够提供类SQL查询功能(HiveQL)而广受欢迎。Hive的设计初衷是为了简化大数据集的查询和管理,它允许用户通…...
minimind - 从零开始训练小型语言模型
大语言模型(LLM)领域,如 GPT、LLaMA、GLM 等,虽然它们效果惊艳, 但动辄10 Bilion庞大的模型参数个人设备显存远不够训练,甚至推理困难。 几乎所有人都不会只满足于用Lora等方案fine-tuing大模型学会一些新的…...
前端知识速记—JS篇:箭头函数
前端知识速记—JS篇:箭头函数 什么是箭头函数? 箭头函数是 ES6 引入的一种新的函数书写方式,其语法更为简洁,常用于替代传统的函数表达式。箭头函数的基本语法如下: const functionName (parameters) > {// 函数…...
小程序的协同工作与发布
1.小程序API的三大分类 2.小程序管理的概念,以及成员管理两个方面 3.开发者权限说明以及如何维护项目成员 4.小程序版本...
计算机网络 笔记 网络层 3
IPv6 IPv6 是互联网协议第 6 版(Internet Protocol Version 6)的缩写,它是下一代互联网协议,旨在解决 IPv4 面临的一些问题,以下是关于 IPv6 的详细介绍: 产生背景: 随着互联网的迅速发展&…...
python 语音识别
目录 一、语音识别 二、代码实践 2.1 使用vosk三方库 2.2 使用SpeechRecognition 2.3 使用Whisper 一、语音识别 今天识别了别人做的这个app,觉得虽然是个日记app 但是用来学英语也挺好的,能进行语音识别,然后矫正语法,自己说的时候 ,实在不知道怎么说可以先乱说,然…...
事务02之锁机制
锁机制 文章目录 锁机制一:MySQL锁的由来与分类1:锁机制的分类 二:共享锁与排他锁1:共享锁(S锁)2:排他锁(X锁)3:锁的释放 二:表级别锁1:元数据锁(了解)2:意向锁3…...
Python NumPy(10):NumPy 统计函数
1 NumPy 统计函数 NumPy 提供了很多统计函数,用于从数组中查找最小元素,最大元素,百分位标准差和方差等。 1.1 numpy.amin() 和 numpy.amax() numpy.amin() 用于计算数组中的元素沿指定轴的最小值。 numpy.amin(a, axisNone, outNone, keep…...
[Spring] Gateway详解
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
TCP三次握手和四次挥手面试题
TCP标志位TCP序列号、确认号三次握手 三次握手过程为什么不是两次握手?为什么不是四次握手? 为什么超时重传?如何处理丢包 为什么需要超时重传?如何处理丢包? 四次挥手 四次挥手过程为什么需要四次挥手为什么四次挥手,…...
使用openAI与Deepseek的感受
今天简单介绍下使用OpenAI和DeepSeek的感觉,有些地方可能存在不准确的地方,望指正: 从2023年的秋冬到现在2025年的1月间,OpenAI和DeepSeek我都用它们来帮我,当然更多的是OpenAI,但整体感受如下:…...
FFmpeg(7.1版本)在Ubuntu18.04上的编译
一、从官网上下载FFmpeg源码 官网地址:Download FFmpeg 点击Download Source Code 下载源码到本地电脑上 二、解压包 tar -xvf ffmpeg-7.1.tar.xz 三、配置configure 1.准备工作 安装编译支持的软件 ① sudo apt-get install nasm //常用的汇编器,…...
为AI聊天工具添加一个知识系统 之80 详细设计之21 符号逻辑 之1
本文要点 要点 前面我们讨论了本项目中的正则表达式。现在我们将前面讨论的正则表达式视为狭义的符号文本及其符号规则rule(认识的原则--认识上认识对象的约束),进而在更广泛的视角下将其视为符号逻辑及其符号原则principle(知识…...
【C++】类和对象(5)
目录 一、构造函数补充1、初始化列表 二、类型转换三、static成员四、友元1、友元函数2、友元类 五、内部类六、匿名对象 一、构造函数补充 对于之前讲解的构造函数,还有一些更深层次的内容要进行补充,接下来进行补充内容的讲解。 1、初始化列表 在我…...
FPGA|使用quartus II通过AS下载POF固件
1、将开发板设置到AS下载挡位,或者把下载线插入到AS端口 2、打开quartus II,选择Tools→Programmer→ Mode选择Active Serial Programming 3、点击左侧Add file…,选择 .pof 文件 →start 4、勾选program和verify(可选࿰…...
H. Mad City
题目链接:Problem - H - Codeforces 题目大意:给定一个带环的图, 以及a, b两点 判断再图上不断的移动, b想不与a相遇, a想捉到b, 并且二者只能移动一步。 若b跑不掉 NO 否则YES. 具体题目看链接 输入: …...
