数据结构第三讲:单链表的实现

数据结构第三讲:单链表的实现

  • 1.什么是单链表
  • 2. 节点
  • 3.单链表的实现
    • 3.1节点的结构
    • 3.2打印单链表
    • 3.3申请一个新节点
    • 3.4单链表尾部插入
    • 3.5单链表头部插入
    • 3.6单链表的尾部删除
    • 3.7单链表头部删除
    • 3.8查找
    • 3.9在指定位置之前插入数据
    • 3.10在指定位置之后插入数据
    • 3.11删除pos节点
    • 3.12删除pos之后的节点
    • 3.13销毁链表

1.什么是单链表

单链表也是顺序表的一种,它在逻辑结构上是连续的,在物理结构上不一定是连续的

就像是火车一样,有一个火车头、很多节车厢,每相邻的车厢会通过钩子进行链接,单链表中,一节一节的车厢被成为是一个一个的节点,就像这样:
在这里插入图片描述

2. 节点

那么每一个节点到底是怎么样来链接的呢?其实每一个节点中只存储两个数据:需要存储的数据和指向下一个节点的指针,这样通过指针就能够找到下一个节点了

3.单链表的实现

3.1节点的结构

节点只需要存储两个内容,所以实现起来也会比较轻松:

typedef int SLTDateType;typedef struct SListNode
{//存储数据SLTDateType date;//存储框架struct SListNode* next;
}SLTNode;

3.2打印单链表

我们先使用节点结构体自行创建一些节点,然后自行将节点链接起来,如下:

	//通过动态内存分配创建节点SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->date = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->date = 2;SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->date = 3;SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));node4->date = 4;SLTNode* node5 = (SLTNode*)malloc(sizeof(SLTNode));node5->date = 5;node1->next = node2;node2->next = node3;node3->next = node4;node4->next = node5;node5->next = NULL;

然后我们实现一下链表的打印功能:
打印我们使用一个while循环即可,因为链表最后一个节点指向的空间为NULL,所以我们可以以此为一个突破点,作为循环的终止条件,实现如下:

void SLTPrint(SLTNode* phead)
{//对于打印,使用一个循环即可SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->date);pcur = pcur->next;}printf("NULL\n");
}

3.3申请一个新节点

上述我们自行申请的一个新节点太过于费事费力了,我们应该试着写一个函数,让函数来帮我们申请空间,实现起来也不困难:

//申请一个新节点
SLTNode* SLBuyNode(SLTDateType x)
{SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));if (node == NULL){perror("malloc faile!");exit(1);}node->date = x;node->next = NULL;return node;
}

3.4单链表尾部插入

看图:
在这里插入图片描述
我们只需要找到链表的末端,将最后一个节点中的地址指向新的节点,然后将新的节点中的指针指向NULL即可:

//单链表尾部插入
//注意:这里要使用二级指针,因为如果链表中没有节点时,我们要改变头指针的值,让它指向第一个节点的地址
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);//对于插入,首先都要先创建一个节点,才能够实现插入SLTNode* newnode = SLBuyNode(x);//插入方法//1.找到最后一个节点if (*pphead == NULL){*pphead = newnode;}else{SLTNode* pcur = *pphead;while (pcur->next){pcur = pcur->next;}pcur->next = newnode;}
}

3.5单链表头部插入

在这里插入图片描述
只需要将刚开辟节点中的指针指向原来的头节点地址,并改变头节点的指向即可:

//单链表头部插入
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = SLBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}

3.6单链表的尾部删除

在这里插入图片描述
只需要将最后一个节点的空间释放掉,然后将释放后的最后一个节点中的指针指向NULL即可,需要注意的是:这里需要找到释放位置前的节点,当只存在一个节点时,最后一个节点前的空间是不能够进行访问的,这里需要单独讨论:

//单链表尾部删除
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//将只有一个节点的情况单独讨论if ((*pphead)->next == NULL)//这里要注意:->的优先级要大于* 所以要将*pphead加上小括号{free(*pphead);*pphead = NULL;}else{//先找到最后一个数据的前一个数据SLTNode* pcur = *pphead;SLTNode* prev = NULL;while (pcur->next){prev = pcur;pcur = pcur->next;}prev->next = NULL;free(pcur);pcur = NULL;}
}

3.7单链表头部删除

在这里插入图片描述
头部删除相对简单,只需要释放空间,然后改变头指针的位置即可:

//单链表头部删除
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* prev = (*pphead)->next;free(*pphead);*pphead = prev;
}

3.8查找

查找查找的是数据所在的位置,返回的是节点的地址:

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDateType x)
{assert(phead);SLTNode* pcur = phead;while (pcur){if (pcur->date == x){return pcur;}pcur = pcur->next;}return NULL;
}

3.9在指定位置之前插入数据

在这里插入图片描述
在指定位置之前插入数据,需要找到指定位置前的那个节点,这里还需要单独讨论,因为当只存在一个节点时,前面的空间是无法访问的,和上边一样,然后我们只需要改变节点中指针的指向即可

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead,SLTNode* pos, SLTDateType x)
{assert(pphead);assert(pos);//当在第一个节点前进行插入时if (*pphead == pos){SLTPushFront(pphead, x);}else{//先创建一个节点SLTNode* newnode = SLBuyNode(x);SLTNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}pcur->next = newnode;newnode->next = pos;}
}

3.10在指定位置之后插入数据

在这里插入图片描述
在指定位置之后插入数据,因为已经知道了在哪个位置进行插入,所以我们就能够直接找到下一个节点的地址,直接改变地址指向即可:

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDateType x)
{assert(pos);//先创建一个节点SLTNode* newnode = SLBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}

3.11删除pos节点

在这里插入图片描述
删除节点,只需要释放空间,改变指针指向即可:

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pos);assert(*pphead && pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}

3.12删除pos之后的节点

在这里插入图片描述
释放空间,改变指向:

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);pos->next = pos->next->next;free(pos->next);pos->next = NULL;
}

3.13销毁链表

在这里插入图片描述

使用循环销毁即可:

//销毁链表
void SListDestory(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* prew = *pphead;while (prew){SLTNode* pcur = prew->next;free(prew);prew = pcur;}*pphead = NULL;
}

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

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

相关文章

VS+opencv+环境配置

下载opencv库。 版本 - OpenCV 下载完了是一个exe文件,(可以更换目录)直接双击,也就是压缩。 vs配置: 调试-调试属性 点编辑,加入这两个,路径根据自己的opencv库 3、链接器 测试:…

在Postman中引用JS库

前言 在做接口测试时,出于安全因素,请求参数需要做加密或者加上签名才能正常请求,例如:根据填写的请求参数进行hash计算进行签名。postman作为主流的接口调试工具也是支持请求预处理的,即在请求前使用JavaScript脚本对…

Redis:AOF持久化

1. 简介 以日志的形式来记录每个写操作,将redis执行的每个写操作记录下来(读操作不记录),只需追加文件但不可以改写文件,redis启动之初会重新构建数据,即redis重启后会将日志中的所有写指令重新执行一遍以达…

扰动观测器DOB设计及其MATLAB/Simulink实现

扰动观测器(Disturbance Observer, DOB)是一种在控制系统中用于估计和补偿未知扰动的重要工具,以增强系统的鲁棒性和稳定性。其设计过程涉及系统建模、观测器结构设计以及控制律的调整。 扰动观测器设计原理 系统建模: 首先,需要建立被控对象的数学模型,明确系统的状态变…

2024第八届全国职工职业技能大赛“网络与信息安全管理员”赛项技术文件及任务书

2024第八届全国职工职业技能大赛“网络与信息安全管理员”赛项技术文件及任务书 一、赛项概述:二、竞赛形式:三、竞赛规则四、竞赛样题4.1、第一场4.1.2、实操闯关赛4.2、第二场4.3、第三场 需要培训可以私信博主 欢迎交流学习! [X] &#x1…

【深入理解SpringCloud微服务】深入理解nacos

【深入理解SpringCloud微服务】深入理解nacos Nacos服务注册内存注册表内存注册表的更新通知客户端服务变更、服务同步、健康检查2.x版本nacos的变化 Nacos服务注册 spring-cloud-alibaba-nacos-discovery通过实现spring-cloud-commons规范定义的接口,完成nacos接入…

昇思25天学习打卡营第11天|xiaoyushao

今天分享ResNet50迁移学习。 在实际应用场景中,由于训练数据集不足,所以很少有人会从头开始训练整个网络。普遍的做法是,在一个非常大的基础数据集上训练得到一个预训练模型,然后使用该模型来初始化网络的权重参数或作为固定特征提…

论文阅读:Deep_Generic_Dynamic_Object_Detection_Based_on_Dynamic_Grid_Maps

目录 概要 Motivation 整体框架流程 技术细节 小结 不足 论文地址:Deep Generic Dynamic Object Detection Based on Dynamic Grid Maps | IEEE Conference Publication | IEEE Xplore 概要 该文章提出了一种基于动态网格图(Dynamic Grid Maps&a…

操作系统面试知识点总结4

#来自ウルトラマンメビウス(梦比优斯) 1 文件系统基础 1.1 文件的相关概念 文件是以计算机硬盘为载体的存储在计算机上的信息集合,可以是文本文档、图片、程序。 文件的结构:数据项、记录、文件(有结构文件、无结构式…

橙单前端项目下载编译遇到的问题与解决

今天下载orange-admin前端项目,不过下载下来运行也出现一些问题。 1、运行出现下面一堆错误,如下: 2、对于下面这个错误 error Expected linebreaks to be LF but found CRLF linebreak-style 这就是eslint的报错了,可能是原作者…

Python学习笔记44:游戏篇之外星人入侵(五)

前言 上一篇文章中,我们成功的设置好了游戏窗口的背景颜色,并且在窗口底部中间位置将飞船加载出来了。 今天,我们将通过代码让飞船移动。 移动飞船 想要移动飞船,先要明白飞船位置变化的本质是什么。 通过上一篇文章&#xff0…

新手小白的pytorch学习第十四弹------十一、十二、十三弹卷积神经网络CNN的习题

习题编号目录 No 1No 2No 3No 4No 5No 6No 7No 8No 9No 10No 11No 12No 13 练习题主要就是 写代码,所以这篇文章大部分是代码哟~ No 1 What are 3 areas in industry where computer vision is currently being used? No 2 工业异常检测,目标检测 Sea…

第三十四天 复合选择器之后代选择器

常用复合选择器包括 后代选择器、子选择器、并集选择器、伪类选择器 后代选择器 语法 选择器1 选择器2{属性:属性值;} 出现重复组可以用类名进行区别 后代选择器可以无限套娃 父子等级可以是人为创造的

利用GPT4o Captcha工具和AI技术全面识别验证码

利用GPT4o Captcha工具和AI技术全面识别验证码 🧠🚀 摘要 GPT4o Captcha工具是一款命令行工具,通过Python和Selenium测试各种类型的验证码,包括拼图、文本、复杂文本和reCAPTCHA,并使用OpenAI GPT-4帮助解决验证码问…

spring IOC DI -- IOC详解

T04BF 👋专栏: 算法|JAVA|MySQL|C语言 🫵 今天你敲代码了吗 文章目录 4.2 Ioc 详解4.2.1 Bean的存储Controller(控制器存储)Service (服务存储)Repository(仓库存储)Component(组件存储)Configuration(配置存储) 4.2.2 为什么需要这么多类注解?4.2.3方法…

面试重点---快速排序

快排单趟 快速排序是我们面试中的重点,这个知识点也很抽象,需要我们很好的掌握,而且快速排序的代码也是非常重要,需要我们懂了还不行,必须要手撕代码,学的透彻。 在研究快速排序之前,我们首先…

depcheck 前端依赖检查

介绍 depcheck 是一款用于检测项目中 未使用依赖项 的工具。 depcheck 通过扫描项目文件,帮助你找出未被引用的依赖,从而优化项目。 优势: 简单易用: 仅需几个简单的命令,就能够扫描并列出未使用的依赖项,让你快速了…

GeneCompass:跨物种大模型用于破解基因调控机理

GeneCompass是第一个基于知识的跨物种基础模型,该模型预先训练了来自人类和小鼠的超过1.2亿个单细胞转录组。在预训练过程中,GeneCompass有效整合了四种生物先验知识,以自监督的方式增强了对基因调控机制的理解。对多个下游任务进行微调&…

PlatformIO+ESP32S3学习:通过WIFI与和风天气API获取指定地点的天气情况并显示

1. 硬件准备 你只需要有一个ESP32S3开发板。我目前使用的是: 购买地址:立创ESP32S3R8N8 开发板 2. 和风天气API 2.1. 和风天气介绍 和⻛天气是中国领先的气象科技服务商、国家高新技术 企业,致力于运用先进气象模型结合大数据、人工智能 技术…