线性表的链式存储结构——链表

一、顺序表优缺点

优点:我们知道顺序表结构简单,便于随机访问表中任一元素;

缺点:顺序存储结构不利于插入和删除,不利于扩充,也容易造成空间浪费。

二、链表的定义

①:概念:

用一组任一的存储单元存储线性表的数据元素(可以是连续,也可以是不可连续的),数据元素之间的逻辑关系借助指示元素存储位置的指针来表示,这种存储方式叫做线性表的 链式存储结构 ,简称 链表

②:结点

为了表示数据元素间的逻辑关系,除了存储数据本身信息之外,还需要存放其直接后继的存储位置(地址),这两部分(数据域和指针域)组成一个 结点 用于表示一个元素。
数据域:存储数据元素的信息;
指针域:存放直接后继的元素的地址。
表示图如下:
同时还需要注意以下几点:
注意:我们规定链表的尾结点(最后一个结点)的指针域为NULL,这样可以方便进行操作。

③:单链表的定义:

若链表的每个结点只包含一个指针域,则称此链表为 线性链表单链表

④:头结点:

有时为了操作方便,在单链表的第一个结点之前添加一个结点,称为 头结点或伪结点
不带哨兵的头结点就直接使用;
带哨兵的头结点就按以下规则:
头结点的数据域可以不存放任何信息,也可以存放其他特殊信息;
头结点的指针域存放第一个结点的存储地址,即指向第一个结点;
本次小编用的是不带哨兵的头结点。
有头结点的单链表叫做“带头结点的单链表”。

三 、单链表的C语言结构定义:

typedef int SLDataType;//方便以后跟改数据类型typedef struct SLisrNode
{SLDataType data;//数据域struct SListNode* next;//指针域
}Lnode, * LinkList;//用typedef重定义后,Londe为结点类型,LinkList为指向结点的指针类型


四、单链表基本操作:

作几点说明

①:为了方便让大家感受一下单链表,所以先实现遍历单链表,让大家体会其结构的韵味;

②:我们一般都默认用带有头结点的单链表;

③:大家一般都会写与控制台有互动的代码,但小编这里只是带大家入门上手,只是简单实现,所以大家可以根据小编的思路自行设计。

④:本次实现小编也是采用多文件操作,没听说过的小伙伴可以大致了解一下,就几句话意思很简单。

⑤:跟往常不一样的是,小编会把详细说明放在注释里面,大家请认真解读,有疑问或没看懂的欢迎大家评论区讨论。

四.1、遍历单链表

源代码:

//遍历单链表
void SLTPrint(SLTNode* phead)
{//一般头指针phead我们都不会动,方便我们多次操作//所以我们可以创建一个临时指针来进行操作SLTNode* tmp = phead;//因为单链表尾结点的指针域为NULL,所以循环条件可以为tmp//当tmp为NULL时,说明链表遍历完成,并且退出循环while (tmp){//打印数据域(打印"->"只是方便展示链表结构)printf("%d->", tmp->data);//因为指针域指向下一个结点,所以可以通过赋值方法找到下一个结点tmp = tmp->next;}//方便展示链表结构,所以末尾打印一个NULLprintf("->NULL\n");
}

四.2、用malloc函数创建新结点

因为指针phead刚开始创建时并没有指向任何结点,需要在程序执行过程中通过按结点的类型向系统申请建立一个新结点,通过调用标准函数malloc动态开辟空间生成,

创建一个新结点,具体格式如下:

phead=(SLTNnode*)malloc(sizeof(SLTNode));

当phead结点不需要时,我们应该用free函数释放空间,收回结点;

因为有多种操作,所以我们将这个操作写成一个函数,方便后续调用;

源代码:

//创建新结点
//因为要返回动态申请的结点,所以有返回类型
SLTNode* BuySLiseNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//判断是否开辟成功if (newnode == NULL){perror("malloc");exit(-1);}//填充数据newnode->data = x;newnode->next = NULL;//返回return newnode;
}

四.3、尾插法

尾插法:顾名思义就是在链表尾部进行插入数据;

大致步骤分为两步:

①:找到链表尾结点(根据尾结点的next域为NULL来作为循环条件进行寻找);

②:将新结点链接到尾结点的next域即可;

源代码即解释如下:

//尾插法
//函数第一个形参是二级指针,是存储链表的地址,用的传址调用
//函数第二个形参是要插入的数据
void SLTPushBack(SLTNode** pphead1, SLTDataType x)
{//得到一个新结点SLTNode* newnode = BuySLiseNode(x);//若链表为空链表,则直接将新结点赋值给链表,因为我们是传址调用,可以改变外面链表的内容if (*pphead1 == NULL){*pphead1 = newnode;}else{//同理将链表拷贝到一个临时结点中便于操作SLTNode* tmp = *pphead1;//①:找到尾结点//因为尾结点的next域为NULL,所以可以作为循环判断条件while (tmp->next == NULL){tmp = tmp->next;}//②:链接tmp->next = newnode;//这里可能有的小伙伴不理解,"觉得这里不也是直接赋值吗,怎么改变外部链表的"?//所以大家就要注意一句话,如下://1.改变结构体,用结构体指针//2.改变结构体指针,要用结构体指针的指针(二级指针)// //上面的pphead就是一个结构体二级指针,用于改变结构体指针//但这里的next是结构体成员,所以我们只需要改变结构体,所以就用结构体指针//而tmp本来就是我们结构头指针拷贝过来的,所以改变了tmp的next就相当于改变了外部链表的尾结点的next}//因为tmp、newnode这些都是局部变量,函数结束后会自动销毁//第二次又会从初始位置开始操作,所以我们不用调整这些变量的值//但链表结点内容不会被销毁,因为我们是用malloc函数在堆区上面申请的空间,只有free后才会销毁
}

测试结果:

void TestList2()
{SLTNode* phead = NULL;//头结点,用于链接新结点//尾插100、200、300SLTPushBack(&phead, 100);SLTPushBack(&phead, 200);SLTPushBack(&phead, 300);//打印SLTPrint(phead);}int main()
{//测试
//	TestSLTist1();TestList2();return 0;
}

运行结果:

四.4、头插法

当我们理解清楚尾插法里面的各种细节后,头插以及后面的操作都会觉得很简单;

头插大致分为

①:将新结点的next域指向首结点;

②:再让头指针指向新结点;

源代码及解释如下:


//头插法
//形参和尾插法是相同的道理
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{//因为我们每一步都要使用不带哨兵的头结点,所以每次都要改变结构体指针// 所以形参用二级指针是必须的,并且不用区分链表是否为空//先得到一个新结点SLTNode* tmp = BuySLiseNode(x);//①:新结点的next域指向首结点tmp->next = *pphead;//②:头结点指向新结点*pphead = tmp;
}

四.5、尾删法

尾删法也涉及到许多细节,大家也需要仔细思考;

因为我们使用的是不带哨兵的头指针,就会涉及改变结构体和改变结构体指针的问题;

只要记住:

改变next和data域就是改变结构体,只需要使用结构体指针;

改变头指针就是改变结构体指针,这时需要结构体二级指针;

尾删法分为三中=种情况:

①:链表为空;

②:链表里面只有一个结点;

③:链表里面有两个或两个以上的结点;

具体细节看注释:
源代码如下:


//头删法
//形参是结构体二级指针,因为分为几种情况,有一种情况会改变结构体指针
void SLTPopBack(SLTNode** pphead)
{//情况一:链表为空则提示删除失败if (*pphead == NULL){printf("此链表为空,无法删除!\n");return;}//情况二:只有一个结点,此时需要使用头指针,所以要用到二级指针//直接用free释放掉头指针即可,因为我们用的是不带哨兵的头指针,头指针指向的就是首元素//又因为只有一个元素,所以直接释放头指针,在将头指针置空即可//if((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{//情况三:有两个及其以上的结点:步骤如下://①:定位到尾结点;//②:释放尾结点;//将尾结点的前一个结点的next域置空(所以一定要保存前一结点的地址)//同理先将链表内容拷贝到临时指针中进行操作,因为我们操作的是结构体,所以用结构体指针即可实现SLTNode* tmp = *pphead;//如果tmp->next->next为NULL,说明tmp->next就是尾结点,tmp就是尾结点的前一个结点,所以就可以进行释放了while (tmp->next->next){tmp = tmp->next;}free(tmp->next);tmp->next = NULL;}
}

四.6、头删法

头删法比较简单,但因为是在头部操作,所以每一步都是在改变结构体指针(即头指针),所以每一步都要用结构体二级指针,所以形参是结构体二级指针;

头删法只有两种情况:

①:链表为空,与尾删一样;

②:链表不为空;这里没有区分一个结点和多个结点是因为我们每一步都要用到结构体二级指针,所以两者操作是一样的;

具体细节即源代码如下:

//头删法
//参数同尾删一样,会改变结构体指针,所以用结构体二级指针
void SLTPopFront(SLTNode** pphead)
{//情况一:链表为空,同尾删一样if (*pphead == NULL){printf("此链表为空,无法删除!\n");return;}//情况二:链表不为空//①:先将第二个结点的地址(即(*pphead->next))保存到临时指针//②:再释放头指针(即释放首元素)//③:再将存放第二个结点地址的临时指针赋给头指针*ppheadSLTNode* nextnode = (*pphead)->next;free(*pphead);*pphead = nextnode;
}

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

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

相关文章

JavaScript高阶班之ES6 → ES11(八)

JavaScript高阶班之ES6 → ES11 1、ES6新特性1.1、let 关键字1.2、const关键字1.3、变量的解构赋值1.3.1、数组的解构赋值1.3.2、对象的解构赋值 1.4、模板字符串1.5、简化对象写法1.6、箭头函数1.7、函数参数默认值1.8、rest参数1.9、spread扩展运算符1.9.1、数组合并1.9.2、数…

docker-compose 网络配置- IP 主机名 hosts配置

docker-compose 配置IP、hostname、hosts配置 配置IP version: "3" networks:bd-network: # 声明网络external: true services:kafka: # 服务名称networks:bd-network: # 连接的网络名称ipv4_address: 172.2.0.102 # 配置IP配置 主机名 version: "3&quo…

mybatis-spring集成数据库连接池开启注解式开发

目录 1. 引入依赖包 2. 集成配置文件 2.1 开启注解式开发 2.2 spring引入外部配置文件 2.3 数据库连接池 2.4 spring整合mybatis 2.5 自动代理 3. 注解式开发的几个常用注解 4. spring-test 附录一&#xff1a;spring常用注解 1. 引入依赖包 <!--spring整合mybat…

网络基础(一)

通信&#xff0c;在古代是通过书信与他人互通信息的意思。 今天&#xff0c;“通信”这个词的外沿已经得到了极大扩展&#xff0c;它目前的大意是指双方或多方借助某种媒介实现信息互通的行为。 如果按照当代汉语的方式理解“通信”&#xff0c;那么古代的互遣使节、飞鸽传书…

IDEA git操作技巧大全,持续更新中

作者简介 目录 1.创建新项目 2.推拉代码 3.状态标识 5.cherry pick 6.revert 7.squash 8.版本回退 9.合并冲突 1.创建新项目 首先我们在GitHub上创建一个新的项目&#xff0c;然后将这个空项目拉到本地&#xff0c;在本地搭建起一个maven项目的骨架再推上去&#xff0…

【KingbaseES】银河麒麟V10 ARM64架构_安装人大金仓数据库KingbaseES_V8R6(CentOS8)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

焕新古文化传承之路,AI为古彝文识别赋能

目录 1 古彝文与古典保护 2 古文识别的挑战 2.1 西文与汉文OCR 2.2 古彝文识别难点 3 合合信息&#xff1a;古彝文保护新思路 3.1 图像矫正 3.2 图像增强 3.3 语义理解 3.4 工程技巧 4 总结 1 古彝文与古典保护 彝文指的是云南、贵州、四川等地的彝族人使用的文字&am…

十九,镜面IBL--BRDF积分贴图

再回顾下镜面部分的分割求和近似法 现在关注第二部分 最后可化为 也就是说&#xff0c;这两部分积分可以获得F0的系数和F0的偏差。 这两个值可以存储到BRDF积分贴图的RG部分。void main() { vec2 integratedBRDF IntegrateBRDF(TexCoords.x, TexCoords.y); FragColor …

驱动开发:STM32F7控制AD5663模拟量输出

AD5663是ADI公司的一款DAC模块&#xff0c;用以实现两路模拟量信号输出。该芯片通过SPI通信来驱动。下面讲解使用STM32F7主控芯片来控制AD5663模拟量输出的流程。 配置STM32F7 SPI通信管脚 STM32CubeMX生成SPI驱动代码 /* SPI3 init function */ void MX_SPI3_Init(void) {/*…

【数据代理+事件处理+计算属性与监视+绑定样式+条件渲染】

数据代理事件处理计算属性与监视绑定样式条件渲染 1 数据代理1.1 回顾Object.defineProperty方法1.2 数据代理 2 事件处理2.1 绑定监听2.2 事件修饰符2.3 键盘事件 3 计算属性与监视3.1 计算属性3.2 监视属性(侦视属性)3.3 watch对比computed 4 绑定样式4.1 绑定class样式4.2 绑…

区块链3.0时代 基于GoMars构建的新概念TravelFi能否注入新力量?

区块链技术进入3.0时代 后疫情时代&#xff0c;全球数字化进程不断加快&#xff0c;世界范围内的移动通信、互联网技术及各类数字化应用的社会普及率也正在快速提升&#xff0c;疫情推动了互联网经济的增长&#xff0c;也让数字经济的价值开始显现。 数字经济一词的由来至今已经…

代码随想录 Day8 栈(FILO)与队列(FIFO) LeetCode T232 用栈实现队列 LeetCodeT225 用队列实现栈

题目详细思路来自于:代码随想录 (programmercarl.com) 栈和队列都是大家不陌生的数据结构,我们之前的栈和队列一般是用数组或链表来实现的 , 这里我们给出实现方式,用于帮助更好的理解. 1.用链表实现栈 /* 基于链表实现的栈 */ class LinkedListStack { private ListNode sta…

Vue3之Suspense

<Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成&#xff0c;并可以在等待时渲染一个加载状态。 我们可以看到官网并不推荐我们使用它&#xff0c;目前仍处于测试中。 他用于加…

VUE2项目:尚品汇-axios二次封装请求以及VUEX的状态管理库

上一篇&#xff1a;VUE2项目&#xff1a;尚品汇VUE-CLI脚手架初始化项目以及路由组件分析&#xff08;一&#xff09; 目录 axios二次封装API接口管理与解决跨域API接口管理nprogress进度条配置 VUEX状态管理库三级分类动态背景颜色防抖三级联动跳转路由分析 axios二次封装 项…

windows系统查看exe程序的依赖dll并拷贝到指定路径下

脚本 echo off REM windows_copy_depends.bat是脚本文件名&#xff0c;exe_path是exe文件的全路径&#xff0c;dll_folder_path是脚本当前路径下的文件夹名称 REM 如windows_copy_depends.bat E:\git_code\windows_docker_desktop\winget.exe 123 echo Usage: windows_copy_dep…

Kafka收发消息核心参数详解

文章目录 1、从基础的客户端说起1.1、消息发送者主流程1.2、消息消费者主流程 2、从客户端属性来梳理客户端工作机制2.1、消费者分组消费机制 1、从基础的客户端说起 Kafka提供了非常简单的客户端API。只需要引入一个Maven依赖即可&#xff1a; <dependency><groupId…

《大师级引导-应对困境的工具与技术》读书笔记1

《大师级引导-应对困境的工具与技术》这个书&#xff0c;十分不错&#xff0c;教练和非教练都可以学习。下面是其中的关于冲突的处理&#xff1a; 定义&#xff1a;双方以解决冲突、说明关系为目的而进行的积极的、具有建设性的对话。 目的&#xff1a;制定双方协议&#xf…

《CTFshow-Web入门》10. Web 91~110

Web 入门 索引web91题解总结 web92题解总结 web93题解 web94题解 web95题解 web96题解 web97题解 web98题解 web99题解总结 web100题解 web101题解 web102题解 web103题解 web104题解 web105题解总结 web106题解 web107题解 web108题解 web109题解 web110题解 ctf - web入门 索…

锚框_的标定

一、查漏补缺、熟能生巧&#xff1a; 1.关于fix.axis.add_patch在原来图像的坐标系同添加 边框的函数的使用&#xff1a; 2.torch.arange( h , device)生成tensor的等差数组: 3.torch.T&#xff08;&#xff09;就是transpose转置操作的函数咯: 4.torch.repeat操作&#xff0c…

【Axure高保真原型】3D圆柱图_中继器版

今天和大家分享3D圆柱图_中继器版的原型模板&#xff0c;图表在中继器表格里填写具体的数据&#xff0c;调整坐标系后&#xff0c;就可以根据表格数据自动生成对应高度的圆柱图&#xff0c;鼠标移入时&#xff0c;可以查看对应圆柱体的数据……具体效果可以打开下方原型地址体验…