一篇博客读懂单链表——Single-List

目录

一、初识单链表

单链表是如何构造的:

单链表如何解决顺序表中的问题:

二、单链表的初始定义 

三、尾插和头插

3.1 新建结点CreateNode

3.2 打印SLTPrint

3.3 尾插SLTPushBack 

3.4 头插SLTPushFront 

四、尾删和头删

4.1 尾删SLTPopBack

4.2 头删SLTPopFront

五、某位置前插入删除

5.1 查找SLTFind

5.2 某位置前插入SLTInsert

5.3 某位置删除SLTErase

六、某位置后插入删除

七、 assert断言 

7.1 SLTPrint断言

7.2 SLTPushBack 和 SLTPushFront 断言

7.3 SLTPopBack 和 SLTPopFront 断言

7.4 SLTInsert 和 SLTErase 断言


顺序表的问题:

1.尾部插入效率还不错,头部或者中间插入删除,需要挪动数据,效率低下

2. size 满了后只能扩容,扩容是有一定消耗的;扩容一般存在一定的空间浪费

我们总结了顺序表的问题,下面我们学习的单链表就可以让这些问题迎刃而解。 

学习要求:掌握C语言的指针、二级指针、动态开辟内存的知识

一、初识单链表

我们首先来回顾一下顺序表中的结构体成员:

顺序表中单个结构体存储着顺序表的表头指针、整个顺序表的数据容量、实际存储的数据容量......

单链表是如何构造的:

链表每个结点会存储一个数据,同时会存储一个指针,这个指针指向下一个结点。

单链表如何解决顺序表中的问题:

链表的每一个结点都是 malloc 出来的,他们的地址并不是连续分配的,如果从头部或者中间插入删除,只需要改动单个结点,无需挪动整个 table ;因为链表的结点是一个一个开辟的,所以也不存在顺序表的空间浪费。

下面我们来看一下链表实际的结构:

在这里我们强调不需要太过于关注链表的物理结构,我们的注意点应该集中在其是个结构体。

二、单链表的初始定义 

这里还是和顺序表一样的套路,把它当成一个工程去做,当然就要分文件啦。

其次,在 .h 文件中我们要做我们的准备工作:

 接下来我们来看一下我们需要对链表做的操作:

三、尾插和头插

在学习尾插之前,我们需要先思考一个问题,为什么在我们的操作中有时候需要传指针而有时候需要传二级指针呢(下面以尾插为例)?

如果要探索这个问题的答案,我们一定要知道我们在尾插时是需要改变指针的值的。如果我们调用函数需要改变 int 的值,我们是不是需要传 int* 来改变我们的实参,而在这里我们需要改变的是SLTDataType* 的值,所以就需要我们传入指针的地址来对指针的值进行修改。

3.1 新建结点CreateNode

 我们在这还需要写一个函数,这个函数可以说是链表插入元素的精髓了,我们在前面了解到了链表插入元素是一个结点一个结点地 malloc 出来的,所以我们在这里写一个 CreateNode 函数来创建我们的新结点,可以极大地减少我们下面的代码量。

3.2 打印SLTPrint

为了方便后续的检测,我们也要先把显示链表内容的函数定义出来:

3.3 尾插SLTPushBack 

3.4 头插SLTPushFront 

这里要注意的是我们先让 NewNode 作为头结点来指向 *pphead (即phead) 以此来找到之前第一个结点的地址,然后我们再将 *pphead 指向 NewNode,在以后遇到需要头插的题目,我们也要使用这种顺序。

四、尾删和头删

4.1 尾删SLTPopBack

尾删肯定要找到最后一个元素,让指向最后一个元素的指针直接指向 NULL ,然后再 free 掉最后一个结点,再查找会后一个结点时,我们需要改变的是指向它地址的指针的值,所以我们就要用 tail->next->next != NULL 作为寻找条件:

欸,我们从图中和代码中不难发现,当 tail 的后两个元素为 NULL 时才能进行判断,那么如果链表中只有一个结点(tail->next == NULL),这时候应该怎么办呢?当然是单独进行判断啦!

下面我们来看一下完整代码:

但是需要注意的是,如果我们在一开始就定义了 tail 指针指向 *pphead ,当 tail == NULL 时, free 掉 tail ,这样的写法在我们删掉最后一个结点时会在 Print() 函数中报错,错误代码如下:

这是为什么呢?原因是如果提前用 tail 接收 *pphead,那么在 free(tail) 后也应该将 *pphead 置为空,如果仅仅将 tail 置空,那我们的 *pphead 就成了野指针,这样当然是不可取的。

4.2 头删SLTPopFront

头删就相对简单很多,只需要改变 *pphead 的指向,再 free 就好。

 

五、某位置前插入删除

在学习某位置插入删除前,我们需要知道的是我们的“某位置”应该如何定位,比较某个结点与我们的目标值?显然是不行的,当有多个结点的值重复时这个想法自然就会被推翻,那我们应该怎么办呢?我们也要设计一个查找函数,将第一个查找到的结点地址返回,再将该地址传入我们的插入删除函数中。

5.1 查找SLTFind

当我们遍历完整个链表却没找到想要的元素时,说明链表中没有该元素,返回 NULL 。

5.2 某位置前插入SLTInsert

首先我们要判断这里是不是头插,如果是头插,我们直接调用头插函数,如果不是,我们继续我们的移形换影大法,插入结点。 

 

在改变 cur->next 前,我们要用临时变量 tmp 接收 cur 下一个结点的地址,这样才能在后面找到。 

5.3 某位置删除SLTErase

因为我们的 SLTFind 函数可以定位到 val==x 的当前结点,所以我们可以用这一特点删除指定位置的元素。当我们要删除的是第一个结点时,我们同样可以调用头删函数。

 

 

六、某位置后插入删除

这里思路比较简单,我们来简单看一下代码:

七、 assert断言 

最后我们当然不能忘记断言,下面我们一起来看看每个函数中需要的断言:

7.1 SLTPrint断言

SLTPrint不用断言,因为我们已经设置了当链表为空时只需打印 NULL

7.2 SLTPushBack 和 SLTPushFront 断言

这两个函数只需要断言 pphead 这个二级指针,因为我们是允许链表为空时的头插尾插的。

7.3 SLTPopBack 和 SLTPopFront 断言

这两个函数不仅要断言 pphead 还要断言 *pphead ,因为当链表中有结点时才可以Pop

7.4 SLTInsert 和 SLTErase 断言

插入和删除函数不仅需要像上面两个函数一样断言 pphead *pphead ,还要断言 pos

下面是我的单链表源代码库,包含了对每个函数测试用的代码,需要的uu可以自行查看:

手撕单链表 - Gitee.com

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

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

相关文章

hub.docker访问不了的问题(一步解决)

暂时我也不清楚,但是下面这个网址可以用(可以先用着)Docker Hub Container Image Library | App Containerization (axlinux.top)https://hub.axlinux.top/

Maya 2024 for Mac(3D建模软件)

Maya 2024是一款三维计算机图形软件,具有强大的建模、动画、渲染、特效等功能,广泛应用于影视、游戏、广告等行业。以下是Maya 2024软件的主要功能介绍: 建模:Maya 2024具有强大的建模工具,包括多边形建模、曲面建模、…

【工程实践】Docker使用记录

前言 服务上线经常需要将服务搬到指定的服务器上,经常需要用到docker,记录工作中使用过dcoker指令。 1.写Dockerfile 1.1 全新镜像 FROM nvidia/cuda:11.7.1-devel-ubuntu22.04ENV WORKDIR/data/Qwen-14B-Chat WORKDIR $WORKDIR ADD . $WORKDIR/RUN ap…

洗地机是智商税吗?洗地机有没有必要买?2023洗地机推荐

传统的扫地拖地方式不仅时间长,被毛孩子和萌娃制造的顽固污渍更是让人头痛不已,高效又有效的地面清洁方式成了我们最大的诉求。目前洗地机受到青睐,异常火爆,也成为一众清洁扫地的选择之一,那洗地机到底是不是智商税呢…

C语言从入门到精通之【printf和scanf函数】

printf()是输出函数,scanf()是输入函数,但是它们的工作原理几乎相同。两个函数都使用格式字符串和参数列表。 printf()函数的格式 printf( 格式字符串, 待打印项1, 待打印项2,…);待打印项1、待打印项2等都是要打印的项。它们可以是变量、常量&#xff…

业务出海之服务器探秘

这几年随着国内互联网市场的逐渐饱和,越来越多的公司加入到出海的行列,很多领域都取得了很不错的成就。虽然出海可以获得更加广阔的市场,但也需要面对很多之前在国内可能没有重视的一些问题。集中在海外服务器的选择维度上就有很大的变化。例…

使用validator实现枚举类型校验

使用validator实现枚举类型校验 前言: 在前端调用后端接口传递参数的过程中,我们往往需要对前端传递过来的参数进行校验,比如说我们此时需要对用户的状态进行更新,而用户的状态只有正常和已删除,并且是在代码中通过枚…

【华为云IaaS基础三件套之----计算ECS、网络EIP、存储EVS】

MD[华为云IaaS基础三件套----计算、网络、存储] 华为云IaaS基础三件套之----计算ECS、网络EIP、存储EVS 说明: 这里只是简单从计算/网络/存储,进行介绍,阐明云上对于云下的优势;因ECS是三者综合,故最后说明。 1.网络----弹性公…

Day02_《MySQL索引与性能优化》

文章目录 一、SQL执行顺序二、索引简介1、关于索引2、索引的类型Btree 索引Btree 索引 三、Explain简介四、Explain 详解1、id2、select_type3、table4、type5、possible_keys6、key7、key_len8、ref9、rows10、Extra11、小案例 五、索引优化1、单表索引优化2、两表索引优化3、…

安装 Lua 的 HTTP 库

首先,你需要安装 Lua 的 HTTP 库。可以使用 LuaRocks 来安装。以下是安装命令: luarocks install http然后,你可以使用以下代码来爬取网页内容: local http require http-- 设置代理信息 http.set_proxy(jshk.com.cn)-- 网页UR…

灵活运用Vue指令:探究v-if和v-for的使用技巧和注意事项

🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、作…

为什么打开idea时,没有启动页面,如何解决?

更新idea2021.2后,当双击idea打开时,发现没有启动界面,直接进入IDEA界面,中间等待时间,让人误以为没有打开idea成功,使得多次点击idea图标。 解决方案就是 在idea界面菜单栏中找到帮助(Help)&a…

全域全自主建设,亚信科技AntDB数据库助力广电5G业务上线运行

自2019年6月,中国广电成功获得5G牌照以来,迅速推进网络建设目标,成为5G网络覆盖广、应用场景多、用户体验出色的第四大运营商。其依托全球独有的700MHz频谱资源,具备覆盖能力强、容量足、速率高的优势。通过不断深化和中国移动的共…

Gempy 实现地理位置3D模型的展示以及导出

1. 首先安装python gempy 包 pip install gempy python 版本 3.10 这个很重要,版本不同可能会报错 2. gdal 可能会报错, 一下地址根据python版本下载,然后移入到python解释器环境中, Script文件中,然后cmd ,pip install 文件名安装即可 Releases cgohlke/geospatial-wheels …

μC/OS-II---计时器管理2(os_tmr.c)

目录 获取计时器的名字获取计时器到期前剩余的时间查看计时器的状态 计时器是倒计时器,当计数器达到零时执行某个动作。用户通过回调函数提供这个动作。回调函数是用户声明的函数,在计时器到期时被调用。在回调函数中绝对不能进行阻塞调用(例…

《008.SpringBoot之教务系统》【界面简洁功能简单】

《008.SpringBoot之教务系统》【界面简洁功能简单】 项目简介 [1]本系统涉及到的技术主要如下: 推荐环境配置:DEA jdk1.8 Maven MySQL 前后端分离; 后台:SpringBootMybatis; 前台:JSPBootStrap; [2]功能模块展示: 管…

[文件读取]coldfusion 文件读取 (CVE-2010-2861)

1.1漏洞描述 漏洞编号CVE-2010-2861漏洞类型文件读取漏洞等级⭐⭐漏洞环境VULFOCUS攻击方式 描述: Adobe ColdFusion是美国Adobe公司的一款动态Web服务器产品,其运行的CFML(ColdFusion Markup Language)是针对Web应用的一种程序设计语言。 A…

Lua的Resty-Request库写的一个简单爬虫

文章目录 准备工作编写爬虫运行爬虫代码分析拓展功能总结 🎉欢迎来到AIGC人工智能专栏~Lua的Resty-Request库写的一个简单爬虫 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页:IT陈寒的博客🎈该系列文章专栏:AIGC人工智…

Git分支与Git标签详解

目录 前言 一、Git分支(Branch) 1.分支的概念 2.分支的常用操作 3.Git 分支管理 二、Git标签(Tag) 1.标签的概念 2.标签的类型 3.标签的常用操作 4.Git标签管理 前言 在软件开发过程中,版本管理是非常重要的一…

【无标题】通用工作站设计方案:ORI-D3R600服务器-多路PCIe3.0的双CPU通用工作站

ORI-D3R600服务器-多路PCIe3.0的双CPU通用工作站 一、机箱功能和技术指标: 系统 系统型号 ORI-SR630 主板支持 EEB(12*13)/CEB(12*10.5)/ATX(12*9.6)/Micro ATX 前置硬盘 最大支持8个3.5寸(兼容25寸)SATA硬盘 2*2.5(后置) 电源类型 CRPS元余电源&#xff0…