一篇博客读懂单链表——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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝牙安全管理(SM:Security Manager)规范详解

总述 配对(Pairing)分为三个阶段,前两个阶段是必须的,而第三阶段是可选的,三个阶段如下: 阶段1:配对功能交换(Pairing Feature Exchange) 阶段2(LE传统配对 LE legacy pairing):短期密钥(STK:Short Term…

【Python大数据笔记_day04_Hadoop】

分布式和集群 分布式:多台服务器协同配合完成同一个大任务(每个服务器都只完成大任务拆分出来的单独1个子任务) 集群:多台服务器联合起来独立做相同的任务(多个服务器分担客户发来的请求) 注意:集群如果客户端请求量(任务量)多,多个服务器同时处理不同请求(不同任务),如果请求量…

为什么推荐从Linux开始了解IT技术

IT是什么,是干什么的呢? 说起物联网,云计算,大数据,或许大家听过。但是,你知道,像云计算的底层基座是什么呢?就是我们现在说的Linux操作系统。而云计算就是跑在Linux操作系统上的一个…

商越科技:渗透测试保障平台安全,推动线上采购高效运转

商越科技是数字化采购解决方案提供商,在同赛道企业中始终保持前列。商越科技通过自主研发的智能采购中台、SaaS应用及运营服务等为企业搭建专属的互联网采购平台,帮助企业实现采购数字化以及智能化转型,提高工作效率、降低采购成本。 打造数字…

自建网盘平台搭建(源码+教程)

为什么要自己搭建网盘,现在许多大厂的网盘,文件都添加了许多限制,有好多文件会遭到和谐,而且大部分网盘也都会限速,不开通VIP是很难用的!这是一套可以运营的网盘,代码无加密可以进行二次开发。下…

【java】【MyBatisPlus】【四】【完】MyBatisPlus一些实战总结(枚举、翻页、sql、组合条件、自增主键、逻辑删除)

目录 一、枚举 1、数据库type字段是Integer 类型枚举 2、创建一个该字段的枚举类 TypeEnum 3、修改实体类 4、配置文件新增mybatis-plus的配置 5、检验: 5.1 查询显示 5.3 库里验证 二、自增主键不是id字段处理 三、逻辑删除字段不是delete字段处理 1、实…

[动态规划] (十四) 简单多状态 LeetCode LCR 091.粉刷房子

[动态规划] (十四) 简单多状态 LeetCode LCR 091.粉刷房子 文章目录 [动态规划] (十四) 简单多状态 LeetCode LCR 091.粉刷房子题目解析解题思路状态表示状态转移方程初始化和填表顺序返回值 代码实现总结 LCR 091. 粉刷房子 题目解析 (1) 一排房子,共有n个 (2) 染…

在任何机器人上实施 ROS 导航堆栈的指南

文章目录 路径规划参考 路径规划 路径规划是导航的最终目标。这允许用户向机器人给出目标姿势,并让它在给定的环境中自主地从当前位置导航到目标位置。这是我们迄今为止所做的一切(地图绘制和本地化)的汇集点。ROS 导航堆栈已经为我们完成了…

CSDN每日一题学习训练——Java版(克隆图、最接近的三数之和、求公式的值)

版本说明 当前版本号[20231109]。 版本修改说明20231109初版 目录 文章目录 版本说明目录克隆图题目解题思路代码思路参考代码 最接近的三数之和题目解题思路代码思路参考代码 求公式的值题目解题思路代码思路参考代码 克隆图 题目 给你无向 连通(https://baike.baidu.com…

Docker两个容器互相请求接口

BEGIN 环境:Docker-Windows-Hyperf 1. 过以下命令查看Docker中的所有网络 docker network ls这个命令会列出所有的Docker网络,包括其ID、名称、驱动以及作用范围 在 Docker 中,容器通过 Docker 网络进行相互通信;在 Docker 中有…

第二十七章 解读Transformer_车道线检测中的Transformer(车道线感知)

前言 近期参与到了手写AI的车道线检测的学习中去,以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新,力求完整精炼,引人启示。所需前期知识,可以结合手写AI进行系统的学习。 SE简单实现 class SELayer(nn.Module):d…

Invalid bound statement (not found)

说明:记录一次Mapper.xml调用数据库存储过程的错误; 报错信息:Invalid bound statement (not found),Mapper的全限定类名 场景:我仔仔细细核对过了方法名,参数,都没有问题,使用插件…

基于 HarmonyOS 的 HTTPS 请求过程开发示例(ArkTS)

介绍 本篇 Codelab 基于网络模块以及 Webview 实现一次 HTTPS 请求,并对其过程进行抓包分析。效果如图所示: 相关概念 ● Webview:提供 Web 控制能力,Web 组件提供网页显示能力。 ● HTTP数据请求:网络管理模块&am…

开发知识点-Django

Django 1 了解简介2 Django项目结构3 url 地址 和视图函数4 路由配置5 请求及响应6 GET请求和POST请求查询字符串 7 Django设计模式及模板层8 模板层-变量和标签9 模板层-过滤器和继承继承 重写 10 url反向解析11 静态文件12 Django 应用及分布式路由创建之后 注册 一下 13 模型…

力扣每日一题 ---- 2905. 找出满足差值条件的下标 II

这道题带有绝对值差的题,一看就是双指针的题,并且还带有两个限制,那么我们的做法就是 固定一个条件,维护一个条件 本题还用到了一个贪心思路,会介绍到 那我们怎么固定一个条件,维护一个条件? …

基于ssm的大学生社团管理系统

基于ssm的大学生社团管理系统 摘要 基于SSM的大学生社团管理系统是一个全面、高效的社团管理平台,旨在帮助大学生和社团管理员更方便、更快捷地进行社团活动的组织和管理。该系统基于Spring、SpringMVC和MyBatis(简称SSM)开发,这三…

CentOS Linux 系统镜像

CentOS Linux具有以下特点: 稳定性:CentOS Linux旨在提供一个稳定、可靠的服务器环境,适合用于关键业务应用和生产环境。高效性:CentOS Linux经过优化和调整,可以充分发挥硬件的性能,提高系统的整体效率。…

selenium自动化测试入门 —— 键盘鼠标事件ActionChains

在使用 Selenium WebDriver 做自动化测试的时候,会经常模拟鼠标和键盘的一些行为。比如使用鼠标单击、双击、右击、拖拽等动作;或者键盘输入、快捷键使用、组合键使用等模拟键盘的操作。在 WebDeriver 中,有一个专门的类来负责实现这些测试场…

DevChat:提升编程效率的AI编程助手

一、DevChat是什么? DevChat是一个集成了多种主流大模型的AI编程工具,专注于提升程序员的编程效率。它整合了ChatGPT、Codex等热门AI大模型,支持自然语言编程、代码编写、代码生成、代码补全等功能。DevChat最大的优势是一站式服务&#xff…

掌握未来技术趋势:深度学习与量子计算的融合

掌握未来技术趋势:深度学习与量子计算的融合 摘要:本博客将探讨深度学习与量子计算融合的未来趋势,分析这两大技术领域结合带来的潜力和挑战。通过具体案例和技术细节,我们将一睹这两大技术在人工智能、药物研发和金融科技等领域…