数据结构——单链表详解(超详细)(2)
前言:
上一篇文章小编简单的介绍了单链表的概念和一些函数的实现,不过为了保证文章的简洁,小编把它分成了两篇来写,这一篇小编紧接上一篇文章继续写单链表函数功能的实现:
目录:
1.单链表剩余函数的编写
1.1.单链表查找数据
1.2.在指定位置之前插入数据
1.3.删除指定结点
1.4.在指定位置之后插入数据
1.5.删除指定位置之后的结点
1.6.单链表的销毁
2.完整的代码呈现
正文:
1.单链表剩余函数的编写
1.1.单链表查找数据
//查找SLTNode* SLTFind(SLTNode* phead, SLdate x);
对于单链表的查找数据,这就类似顺序表的查找数据,我们要遍历所有的单链表,直到找到我们想要的数据位置,加入没有我们想要的数据,那么我们可以直接返回一个空地址就好了,此时我们不必再传单链表指针的地址了,因为我们本质上并没有对头结点进行改变 ,所以我们仅需把头节点传过去就可以,在函数内部,我们想要遍历顺序表,就要采用循环,来进行一个一个结点的查找,下面是代码呈现:
SLTNode* SLTFind(SLTNode* phead, SLdate x)
{SLTNode* pour = phead;while (pour){if (pour->date == x){return pour;}pour = pour->next;}return NULL;
}
1.2.在指定位置之前插入数据
这里我们可以用到我们上面用到的查找函数,因为它是返回的结点,所以我们可以通过它来确定我们想要的指定位置,因为单链表只可以往后一步一步的走,而不能往前找数据,所以我们得先确认我们想要找的位置,下面我们涉及指定位置的时候,都要引用一下查找指定位置这个函数,下面我们来进行这个函数的讲解,这个函数其实也分为两种情况
第一种情况是指定位置就是头结点,此时这就类似于我们之前写过的头插函数,我们直接引用头插函数就可以实现这个功能。
第二种情况就是普通情况,我们要在指定位置之前插入数据,所以我们需要找到指定位置之前的数据,所以这里我们要用用到头结点,并且用到前面讲的创建新结点的函数(因为此文章涉及了不少插入数据的函数,所以我会把创建新结点的代码再写一遍!),我们让一个结点放入头结点数据,然后一步一步往后走,直到走到指定位置之前,之后我们可以讲新节点的下一个结点设置为指定结点,然后再把之前指定位置之前的结点的下一个结点设置为新结点,这里我们便可以完成在指定位置之后插入数据,下面小编先给上图文解释:
新结点的创建:
SLTNode* SLTbuynode(SLdate x)
{SLTNode* pour = (SLTNode*)malloc(sizeof(SLTNode));assert(pour);pour->date = x;pour->next = NULL;return pour;
}
头插函数:
void SLTPushFront(SLTNode** pphead, SLdate x)
{assert(pphead);SLTNode* newnode = SLTbuynode(x);newnode->next = *pphead;*pphead = newnode;
}
函数部分:
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x)
{assert(pos && pphead && *pphead);if (pos == *pphead){SLTPushFront(pphead,x); //这个是头节点就是pos的特殊情况,我们在指定位置之前插入数据的时候,是会先找到指定位置之前的数据以及之后的,头节点的话找不到数据了}else{SLTNode* newnode = SLTbuynode(x);SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);newnode->next = pour;pur->next = newnode;}
1.3.删除指定结点
删除指定结点的操作,同样也和上面的函数一样,我们也分为两种情况进行讨论:
第一种情况就是我们想要删除的指定节点就是头结点,此时我们只需要调用一下头删函数就可以实现。
第二种情况自然就是普通情况,此时我们依旧需要用到头结点,因为我们需要知道指定结点之前的结点,之后我们只需要让前一个结点的下一个结点直接指向指定结点的下一个结点,之后我们在把指定节点给释放掉,就可以实现指定节点删除操作,下面小编先给上图文解释:
头删函数:
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pour = *pphead;*pphead = (*pphead)->next;free(pour);pour = NULL;
}
删除指定结点函数:
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead && pos <= *pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);pur -> next = pur->next -> next;free(pour);pour = NULL;}
}
1.4.在指定位置之后插入数据
小编在上面已经讲述了指定位置之前如何插入数据了,那么现在可以讲述在指定位置之后插入数据了,这个其实比上面那个简单多了,因为此时我们不需要用到指定位置之前的结点了,所以我们不必在使用头结点了,此时我们依然需要先创建一个新节点,之后我们在讲新结点之后的结点变为我们指定位置之后的结点,指定位置之后的结点·在指向新节点,这里就可以实现在指定位置之后插入新数据了,下面小编先给上图文解释,再给上代码呈现:
void SLTInsertAfter(SLTNode* pos, SLdate x)
{assert(pos);SLTNode* newnode = SLTbuynode(x);newnode->next = pos->next;pos->next = newnode;
}
1.5.删除指定位置之后的结点
有插入必会有删除,下面我们将要讲述最后一个重要的函数,那么就是删除指定位置之后的结点,这个,同样也是非常的简单,我们只需要把指定结点的下一个结点变为下一个的下一个的结点,再把原来指定位置之后的结点释放掉就好了,下面我们直接给出图像说明:
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* pour = pos -> next;pos->next = pos->next->next;free(pour);pour = NULL;
}
1.6.单链表的销毁
单链表有创建,自然就会有销毁,单链表的销毁也不算很难,毕竟难的部分都在上面,轻舟已过万重山,对于单链表的销毁其实就是把每个结点给free掉,我们可以设置一个指针作为头结点,在设置一个指针用来给予上一个指针,每销毁完一个结点,我们把第二个指针的内容给予第一个指针,然后让第二个指针继续往后走,这样我们通过循环的知识可以做到每个结点的删除,循环结束完以后,别忘了对头结点进行销毁,这样我们便可以完成对于单链表的销毁了,下面直接给上代码:
void SListDestroy(SLTNode** pphead)
{assert(*pphead && pphead);SLTNode* pour = *pphead;while (pour){SLTNode* next = pour->next;free(pour);pour = next;}*pphead = NULL;
}
2.完整的代码呈现
现在,小编已经把单链表大部分内容给讲完了,但单链表实现的功能远不止这些,感兴趣的读者朋友可以再继续探索,小编这里给上大家单链表的完整代码:
SList.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLdate; //方便后面整体类型的改变//创立一个单链表
typedef struct Slist {//先设置一个类型SLdate date;struct Slist* next; //存放下一个节点的地址
}SLTNode;//链表的打印
void SLTprintf(SLTNode* phead);//开始正式环节了
//尾插
void SLTPushBack(SLTNode** pphead, SLdate x);//头插
void SLTPushFront(SLTNode** pphead, SLdate x);//尾删
void SLTPopBack(SLTNode** pphead);//头删void SLTPopFront(SLTNode** pphead);//查找SLTNode* SLTFind(SLTNode* phead, SLdate x);//在指定位置之前插入数据void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x);//删除pos节点void SLTErase(SLTNode** pphead, SLTNode* pos);//在指定位置以后插入数据void SLTInsertAfter(SLTNode* pos, SLdate x);//删除pos之后的节点void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDestroy(SLTNode** pphead);
SList.c
#include"SList.h"
void SLTprintf(SLTNode* phead)
{SLTNode* pour = phead; //这么做是为了保证头节点不会发生改变while (pour){printf("%d->", pour->date);pour = pour->next;}printf("NULL\n");
} //这个操作是打印单链表的数据SLTNode* SLTbuynode(SLdate x)
{SLTNode* pour = (SLTNode*)malloc(sizeof(SLTNode));assert(pour);pour->date = x;pour->next = NULL;return pour;
}void SLTPushBack(SLTNode** pphead, SLdate x)
{//首先可以先建一个函数,这个函数是来开辟一个新节点的(后面想要插入直接调用就好了)assert(pphead);SLTNode * p = SLTbuynode(x);if (*pphead == NULL) //首先判断{*pphead = p;}else{SLTNode* pour = *pphead;while (pour -> next){pour = pour->next;}pour->next = p;}
}void SLTPushFront(SLTNode** pphead, SLdate x)
{assert(pphead);SLTNode* newnode = SLTbuynode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);if ((*pphead)->next == NULL){*pphead = NULL;}else{SLTNode* pour = *pphead;SLTNode* plist = NULL;while (pour->next){plist = pour;pour = pour->next;}plist->next = NULL;free(pour);pour = NULL;}
}void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pour = *pphead;*pphead = (*pphead)->next;free(pour);pour = NULL;
}SLTNode* SLTFind(SLTNode* phead, SLdate x)
{SLTNode* pour = phead;while (pour){if (pour->date == x){return pour;}pour = pour->next;}return NULL;
}void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x)
{assert(pos && pphead && *pphead);if (pos == *pphead){SLTPushFront(pphead,x); //这个是头节点就是pos的特殊情况,我们在指定位置之前插入数据的时候,是会先找到指定位置之前的数据以及之后的,头节点的话找不到数据了}else{SLTNode* newnode = SLTbuynode(x);SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);newnode->next = pour;pur->next = newnode;}
}void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead && pos <= *pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);pur -> next = pur->next -> next;free(pour);pour = NULL;}
}void SLTInsertAfter(SLTNode* pos, SLdate x)
{assert(pos);SLTNode* newnode = SLTbuynode(x);newnode->next = pos->next;pos->next = newnode;
}void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* pour = pos -> next;pos->next = pos->next->next;free(pour);pour = NULL;
}void SListDestroy(SLTNode** pphead)
{assert(*pphead && pphead);SLTNode* pour = *pphead;while (pour){SLTNode* next = pour->next;free(pour);pour = next;}*pphead = NULL;
}
总结:
可算快马加鞭的肝完这篇文章了,小编本来想上一篇文章就结束单链表的,但是觉得万字文章有点太多了内容,于是分装成两篇来书写,因为小编是学完了单链表就开始写的文章,有一些地方可能有错误或者文笔显得很繁琐,各位读者朋友见谅,如果有错误的话,恳请在评论区指出,小编会及时的更正,那么,我们下一篇文章见啦!
相关文章:

数据结构——单链表详解(超详细)(2)
前言: 上一篇文章小编简单的介绍了单链表的概念和一些函数的实现,不过为了保证文章的简洁,小编把它分成了两篇来写,这一篇小编紧接上一篇文章继续写单链表函数功能的实现: 目录: 1.单链表剩余函数的编写 1.…...

类和对象(2
*续上文中的运算符重载 4 重载运算符时,有前置和后置的,运算符重载的函数名都是operator, 无法很好区分 所以c规定,后置重载时,增加一个int形参 与前置做区分 5 重载<<和>>时需要重载为全局函数, 因为重载为成员函数时, this指针默认抢占了第一个形参位, 第一个形参…...

AcWing 668. 游戏时间2
读取四个整数 A,B,C,D𝐴,𝐵,𝐶,𝐷,用来表示游戏的开始时间和结束时间。 其中 A𝐴 和 B𝐵 为开始时刻的小时和分钟数,C𝐶 和 D𝐷 为结束时刻的小时和分钟数。…...

AI发展下的伦理挑战,应当如何应对?
针对人工智能(AI)发展中面临的伦理挑战,构建一个全面、有效的治理体系至关重要。以下是对三大关键方向——隐私保护、算法公正与透明度、深度伪造管控——的深入探讨与具体实践方案: 方向一:构建可靠的AI隐私保护机制…...

Java面试题--JVM大厂篇之深入解析JVM中的Serial GC:工作原理与代际区别
目录 引言: 正文: 一、Serial GC工作原理 年轻代垃圾回收(Minor GC): 老年代垃圾回收(Major GC或Full GC): 二、年轻代和老年代的区别 年轻代(Young Generation&a…...

网络安全高级工具软件100套
1、 Nessus:最好的UNIX漏洞扫描工具 Nessus 是最好的免费网络漏洞扫描器,它可以运行于几乎所有的UNIX平台之上。它不止永久升级,还免费提供多达11000种插件(但需要注册并接受EULA-acceptance–终端用户授权协议)。 它…...

Ubuntu 添加gcc头文件搜索路径
对个人用户生效 sudo vim ~/.bashrc在该文件末尾添加 #gcc C_INCLUDE_PATH$C_INCLUDE_PATH:your_path export C_INCLUDE_PATH #g CPLUS_INCLUDE_PATH$CPLUS_INCLUDE_PATH:your_path export CPLUS_INCLUDE_PATH最后,重启终端即可生效 可用以下命令查看搜索路径 ec…...

c++写数据结构进入文件
以下定义一个数据结构 struct SData {std::string url;int number;std::string memo; };写入文件 void StorageDataToFile(const std::string& filename, const SData& data) {std::ofstream outFile(filename);if (outFile.is_open()) {// 使用std::stringstream格式…...

Java实验4
实验内容 考试题 要求在一个界面内至少显示5道选择题,每道题4个选项。题目从数据库读取。表结构自定义。 另有2个命令按钮,分别为“重新答题”(全部选项及正确答题数清空)和“提交”(计算),在…...

优化 Java 数据结构选择与使用,提升程序性能与可维护性
优化 Java 数据结构选择与使用,提升程序性能与可维护性 引言 在软件开发中,数据结构的选择是影响程序性能、内存使用以及代码可维护性的关键因素之一。Java 作为一门广泛使用的编程语言,提供了丰富的内置数据结构,如数组、链表、…...

华为USG6000V防火墙安全策略用户认证
目录 一、实验拓扑图 二、要求 三、IP地址规划 四、实验配置 1🤣防火墙FW1web服务配置 2.网络配置 要求1:DMZ区内的服务器,办公区仅能在办公时间内(9:00-18:00)可以访问,生产区的设备全天可以访问 要求2:生产区不…...

Windows 应急响应手册v1.2 -百度网盘下载
家好,《Windows 应急响应手册 v1.2》 发布啦! 本次是一个大更新,解决了两个大问题,添加了4个大的事件处置流程以及一些更新,下载链接在文末 两个大问题是: Windows 平台的 Adobe acrobat DC 、Firefox 浏…...

Billu_b0x靶机
信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令: arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令: nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…...

GitHub+Picgo图片上传
Picgo下载,修改安装路径,其他一路下一步! 地址 注册GitHub,注册过程不详细展开,不会的百度一下 地址 新建GitHub仓库存放图片 ——————————————————————————————————————————…...

springboot的事务管理
在yml配置文件中添加以下:logging.level.org.springframework.jdbc.support.JdbcTransactionManagerdebug...

深入解析rsync:定义、架构、原理、应用场景及实战指南
前言 在现代数据管理和传输过程中,数据同步工具起着至关重要的作用。特别是在需要高效、可靠地在不同服务器或设备之间传输大量数据时,选择一款优秀的数据同步工具显得尤为重要。在众多工具中,rsync以其高效、灵活、可靠的特点,成…...

discuz手机版发帖提示“网络出现问题,请稍后再试”
大家好,我是网创有方。今天分享一个discuz发帖报错的问题。 问题描述:discuz手机网页端发帖提示“网络出现问题,请稍后再试”,但是实际上帖子已经发布成功。 本次记录下分析过程: 第一步:打开宝塔&#…...

图片如何去水印,PS 图片去水印的几种常见方法
在数字图像的世界里,水印常常被用来标识版权或防止未经授权的使用,但有时它们却成为了美观的障碍。无论是出于个人偏好还是专业需求,去除图片上的水印已经成为一项常见的任务。 Adobe Photoshop 作为行业标准的图像编辑软件,提供…...

【从零开始实现stm32无刷电机FOC】【实践】【5/6 stm32 adc外设的高级用法】
目录 采样时刻触发采样同步采样 点击查看本文开源的完整FOC工程 本节介绍的adc外设高级用法用于电机电流控制。 从前面几节可知,电机力矩来自于转子的q轴受磁力,而磁场强度与电流成正比,也就是说电机力矩与q轴电流成正相关,控制了…...

2407-mysql笔记
数据库(Database),简称db mariadbmysql 常见的数据库:mysql、oracle、高斯(Gauss)、redis、sqlserver、SQLite、HBase 一、SQL(Structured Query Language):结构化查询语言 1、作用ÿ…...

如何解决隐藏游戏服务器的源IP问题
在网络游戏领域,保护服务器的源IP地址不被轻易发现是一项重要的安全措施。游戏服务器的源IP一旦暴露,可能会遭受DDoS攻击、扫描和各种形式的安全威胁。然而,对于合法的游戏运营商而言,有时需要对服务器进行维护或调试,…...

云计算数据中心(一)
目录 一、云数据中心的特征二、云数据中心网络部署(一)改进型树结构(二)递归层次结构(三)光交换网络(四)无线数据中心网络(五)软件定义网络 一、云数据中心的…...

libwebrtc.a+exosip连接fS 环境部署tips
//运行FS服务器 sudo ./freeswitch -nc -nonat //公网sudo ./freeswitch //运行客户端 sudo ./fs_cli //加载模块 load mod_av load mod_verto0.Invite交互过程 1.fs码率设置 2.用户密码改动 3.数字签名的摘要 4.FS收不到ACK 5.公网部署 6.查看frewswitch都占用哪些端口 7.日志…...

第二证券:市场估值依然处于较低区域 适合中长期布局
A股中报成绩预告显示相比2024Q1,2024Q2企业产品销量或订单已有回暖,但价格反转暂未大面积到来,“量增价平、部分板块以价换量”是2024H1 A股成绩预告较显着的量价特征,这与微观库存周期有待回暖相匹配。此外中游部分环节出现不同程…...

开始Linux之路
人生得一知己足矣,斯世当以同怀视之。——鲁迅 Linux操作系统简单操作指令 1、ls指令2、pwd命令3、cd指令4、mkdir指令(重要)5、whoami命令6、创建一个普通用户7、重新认识指令8、which指令9、alias命令10、touch指令11、rmdir指令 及 rm指令(重要)12、man指令(重要…...

leetcode-三数之和
视频:https://www.bilibili.com/video/BV1bP411c7oJ/?spm_id_from333.788&vd_sourcedd84879fcf1be72f360461b01ecab0d6 从两数之和开始,排序后的两数之和,利用好升序的性质,可以将时间复杂度从on2降到on; class Solution …...

opencv—常用函数学习_“干货“_总
同样内容将拆解为一份份,发在我个人博客中 如http://t.csdnimg.cn/icOfX(非VIP文章),整理不易、感谢你的点赞收藏 目录 一、图像文件 1. imread:读取图像文件 2. imwrite:写入图像文件 3. imshow:显示图像 4. VideoCapture:捕获视频 二、创建Mat 1、创建Mat对…...

Spring Boot项目的控制器貌似只能get不能post问题
我这2天新建了一个Spring Boot项目测试,在控制器上写了两个接口,一个是支持Get方式访问,另一个支持Post方式访问,发现Get可以,而Post不行。前端Post后,报403,找不到这个方法。 一、原因 原因是…...

最新版智能修图-中文luminar ai 1.55(13797) 和 neo1.20,支持m芯片和intel芯片(绝对可用)
一。Luminar AI for macOS 完整版本 这个程序是第一个完全由人工智能驱动的图像编辑器。有了它,创建引人注目的照片是有趣的,令人惊讶的容易。它是一个独立的照片编辑器和macOS插件。 1.1 Luminar AI for macOS 轻轻地塑造和完善一个肖像打造富有表现…...

Open3D 最小二乘法拟合点云平面
目录 一、概述 1.1最小二乘法原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始点云 3.2matplotlib可视化 3.3平面拟合方程 前期试读,后续会将博客加入该专栏,欢迎订阅 Open3D点云算法与点云深度学习…...