深入浅出链表
目录
1.链表的基本概念及结构
1.1基本概念
1.2结构
2.链表的分类
3.链表的实现(循环链表增删查改实现)
1.动态申请节点(结点)编辑
2.单链表打印
3.单链表尾插
4.单链表头插
5.单链表尾删
6.单链表头删
7.单链表查找
8.在指定位置之前插入数据
9.在指定位置之后插入数据
10.删除pos节点
11.删除pos之后的节点
12.销毁链表
1.链表的基本概念及结构
链表是一种常见的基础数据结构,它由一系列节点(Node)组成,每个节点包含数据和到下一个节点的引用(指针)。以下是链表的基本概念及其结构:
1.1基本概念
-
节点(Node):链表的基本单元,每个节点包含两部分,一部分是存储数据的域(称为数据域),另一部分是存储下一个节点地址的域(称为指针域或链接域)。
-
头节点(Head):链表的第一个节点,通常用于表示整个链表。
-
尾节点(Tail):链表的最后一个节点,其指针域通常指向NULL,表示链表的结束。
-
链表的长度:链表中节点的数量。
-
链表的遍历:按照节点间的链接顺序访问链表中的每个节点。
-
动态性:链表的大小不是固定的,可以在运行时动态地增加或减少节点。
1.2结构
在C语言中,链表节点通常使用结构体(struct)来定义。以下是链表节点的一个基本结构:

链表的结构就像是火车一样一节一节的连在一起。

但是每个节点的地址并不像顺序表一样是连续的,而是随机存储的,因此每个节点才需要下一个节点的地址来找到下一节点。

2.链表的分类
-
单向链表(Singly Linked List):
- 每个节点包含一个数据域和一个指向下一个节点的指针。
- 遍历链表只能从头节点开始,并且只能向一个方向进行。
-
双向链表(Doubly Linked List):
- 每个节点包含一个数据域、一个指向前一个节点的指针和一个指向下一个节点的指针。
- 可以从两个方向遍历链表。
-
循环链表(Circular Linked List):
- 单向链表的变种,最后一个节点的指针指向头节点,形成一个环。
- 可以从任意节点开始遍历整个链表。
-
双向循环链表(Doubly Circular Linked List):
- 双向链表的变种,头节点的前一个指针指向最后一个节点,最后一个节点的下一个指针指向头节点,形成一个环。
- 可以从任意节点开始,向前或向后遍历整个链表。
3.链表的实现(循环链表增删查改实现)


1.动态申请节点(结点)

-
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));:使用malloc函数动态分配一个SLTNode大小的内存块,并将其强制转换为SLTNode*类型的指针。sizeof(SLTNode)获取SLTNode结构体的大小。 -
if (newnode == NULL):检查malloc是否成功分配了内存。如果newnode是NULL,说明内存分配失败。 -
perror("malloc fail!");:如果内存分配失败,使用perror函数打印错误消息。 -
exit(1);:如果内存分配失败,终止程序执行,返回错误代码1。 -
newnode->data = x;:将传入的参数x赋值给新节点的数据域。 -
newnode->next = NULL;:将新节点的指针域初始化为NULL,表示当前节点后面没有其他节点。 -
return newnode;:返回新创建的节点。
2.单链表打印

3.单链表尾插

-
assert(pphead);:使用assert宏来确保传入的头节点指针的指针不是NULL。如果pphead是NULL,程序将终止执行。 -
SLTNode* newnode = SLTBuyNode(x);:调用之前定义的SLTBuyNode函数来创建一个新的节点,并将数据x存储在新节点的数据域。 -
if (*pphead == NULL):检查链表是否为空。如果链表为空(即头节点指针为NULL),则将新节点设置为头节点。 -
else:如果链表不为空,则需要找到链表的最后一个节点。 -
SLTNode* ptail = *pphead;:初始化一个指针ptail,指向头节点。 -
while (ptail->next):遍历链表,直到找到最后一个节点(即节点的next指针为NULL)。 -
ptail = ptail->next;:在循环中,将ptail移动到下一个节点。 -
ptail->next = newnode;:当找到最后一个节点时,将其next指针指向新创建的节点,从而将新节点添加到链表的末尾。
4.单链表头插

-
assert(pphead);:使用assert宏来确保传入的pphead不是NULL。如果pphead是NULL,程序将在这里终止。 -
SLTNode* newnode = SLTBuyNode(x);:调用SLTBuyNode函数创建一个新的节点,并将数据x存储在新节点的数据域中。 -
newnode->next = *pphead;:将新节点的next指针指向原来的头节点。这一步是为了将新节点插入到链表的头部。 -
*pphead = newnode;:更新头节点指针,使其指向新创建的节点。这样,新节点就成为了链表的新头部。
5.单链表尾删

这个接口的实现一开始先要判断链表是否为单节点链表,如果是则直接释放头节点,不是则进行相应的操作。
-
assert(pphead && *pphead);:使用assert宏来确保传入的pphead不是NULL,且链表不为空。如果这些条件不满足,程序将在这里终止。 -
if ((*pphead)->next == NULL):检查链表是否只有一个节点。如果是,直接释放这个节点,并将头节点指针设置为NULL。 -
else:如果链表有多个节点,需要遍历链表找到最后一个节点。 -
while (ptail->next):遍历链表直到ptail指向最后一个节点。 -
free(ptail);:释放最后一个节点的内存。 -
ptail = NULL;:将ptail指针设置为NULL,防止野指针。 -
prev->next = NULL;:将倒数第二个节点的next指针设置为NULL,断开与已删除节点的连接。
6.单链表头删

这里的(*pphead)->next不能写成*pphead->next 因为->预算符优先级是高于*的。
-
assert(pphead && *pphead);:使用assert宏来确保传入的pphead不是NULL,且链表不为空。如果这些条件不满足,程序将在这里终止。 -
SLTNode* next = (*pphead)->next;:保存头节点的下一个节点指针。这是因为一旦释放头节点,我们就无法访问链表的其余部分。 -
free(*pphead);:释放头节点的内存。 -
*pphead = next;:更新头节点指针,使其指向原来的第二个节点(现在成为新的头节点)。
7.单链表查找

-
assert(phead);:使用assert宏来确保传入的phead不是NULL。如果phead是NULL,程序将在这里终止。 -
SLTNode* plist = phead;:初始化一个指针plist,使其指向头节点。 -
while (plist):开始循环,当plist不为NULL时继续执行。 -
if (plist->data == x):检查当前节点的数据是否与要查找的值x匹配。 -
return plist;:如果找到匹配的节点,返回该节点。 -
plist = plist->next;:如果没有找到匹配的节点,移动plist到下一个节点。 -
return NULL;:如果在链表中没有找到匹配的节点,返回NULL。
8.在指定位置之前插入数据

9.在指定位置之后插入数据

-
assert(pphead && *pphead);:使用assert宏来确保传入的pphead不是NULL,且链表不为空。如果这些条件不满足,程序将在这里终止。 -
assert(pos);:使用assert宏来确保传入的pos不是NULL。如果pos是NULL,程序将在这里终止。 -
SLTNode* newnode = SLTBuyNode(x);:调用SLTBuyNode函数创建一个新的节点,并将数据x存储在新节点的数据域中。 -
if (pos == *pphead):检查插入的位置是否是头节点。如果是,使用SLTPushFront函数在头节点位置插入新节点。 -
else:如果插入的位置不是头节点,需要找到pos的前一个节点。 -
SLTNode* prev = *pphead;:初始化prev指针指向头节点。 -
while (prev->next != pos):遍历链表直到找到pos的前一个节点。 -
newnode->next = pos;:将新节点的next指针指向pos。 -
prev->next = newnode;:将pos的前一个节点的next指针指向新节点。
10.删除pos节点

-
assert(pphead && *pphead);:使用assert宏来确保传入的pphead不是NULL,且链表不为空。如果这些条件不满足,程序将在这里终止。 -
assert(pos);:使用assert宏来确保传入的pos不是NULL。如果pos是NULL,程序将在这里终止。 -
if (pos == *pphead):检查要删除的节点是否是头节点。如果是,使用SLTPopFront函数执行头删操作。 -
else:如果要删除的节点不是头节点,需要找到该节点的前一个节点。 -
SLTNode* prev = *pphead;:初始化prev指针指向头节点。 -
while (prev->next != pos):遍历链表直到找到pos的前一个节点。 -
prev->next = pos->next;:将pos的前一个节点的next指针指向pos的下一个节点,完成删除操作。 -
free(pos);:释放pos节点的内存。 -
pos = NULL;:将pos指针设置为NULL,防止野指针。
11.删除pos之后的节点

-
assert(pos);:使用assert宏来确保传入的pos不是NULL。如果pos是NULL,程序将在这里终止。 -
SLTNode* newnode = SLTBuyNode(x);:调用SLTBuyNode函数创建一个新的节点,并将数据x存储在新节点的数据域中。 -
newnode->next = pos->next;:将新节点的next指针指向pos的下一个节点,这样新节点就位于pos的后面。 -
pos->next = newnode;:将pos的next指针指向新节点,完成新节点的插入操作。
12.销毁链表

-
assert(pphead && *pphead);:使用assert宏来确保传入的pphead不是NULL,且链表不为空。如果这些条件不满足,程序将在这里终止。 -
SLTNode* pcur = *pphead;:初始化一个指针pcur,使其指向头节点。 -
while (pcur):开始循环,当pcur不为NULL时继续执行。 -
SLTNode* next = pcur->next;:保存pcur的下一个节点的指针,因为pcur将被释放。 -
free(pcur);:释放pcur节点的内存。 -
pcur = next;:移动pcur指针到下一个节点。 -
*pphead = NULL;:循环结束后,将头指针设置为NULL,表示链表已被销毁。
相关文章:
深入浅出链表
目录 1.链表的基本概念及结构 1.1基本概念 1.2结构 2.链表的分类 3.链表的实现(循环链表增删查改实现) 1.动态申请节点(结点)编辑 2.单链表打印 3.单链表尾插 4.单链表头插 5.单链表尾删 6.单链表头删 7.单链表查找 …...
Linux核心命令入门
Linux常用命令 文件管理文件目录管理文件查看编辑 系统管理网络管理hostnamehost/nslookuptraceroutenetstat列出所有端口 (包括监听和未监听的)列出所有处于监听状态的 Sockets显示每个协议的统计信息 硬件管理df(Disk Free)du(Disk Usage&a…...
腾讯无界微前端框架介绍
一、无界微前端框架概述 无界微前端框架是由腾讯团队推出的,旨在解决现有微前端方案中存在的问题,如适配成本高、样式隔离困难、运行性能不佳、页面白屏、子应用通信复杂、子应用保活机制缺乏等。 技术实现 无界微前端的核心技术是基于Web Component…...
Linux——网络(2)
一、通信 --- 不同主机上进程间的通信 1、IP和端口号 IP:标识网络中的一台主机 本质上 32位的整型数据 端口号: 标识某个进程 本质上 16位的整型数据 2、udp和tcp udp的特点: 1.无连接 2.不可靠 tcp的特点: 1.面…...
结合量子技术解决数据传输安全
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 接前篇:数采网关面…...
【Rust光年纪】提高开发效率:深入了解Rust语言中的数据库客户端和文件处理库
深入探索:Rust语言中多款数据库客户端与文件处理库详解 前言 在现代软件开发中,使用各种数据库和文件处理操作是非常常见的。Rust语言作为一种快速、安全、并发的系统编程语言,也拥有丰富的生态系统和库。本文将介绍几个用于Rust语言的数据…...
【自动驾驶】控制算法(一)绪论与前期准备
写在前面: 🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝 个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。 🔍 本文系 清流君 原创之作&…...
CSDN创作一周年总结
一周年总结 文章目录 一周年总结我的第一篇文章这一年我收获到了什么?1.培养了逻辑能力2.形成了自己的知识库,知识网络3.功利性的收获 我的第一篇文章 不知不觉之间,也已经过去一年了。还记得第一次决定在csdn上写博客,是因为进入…...
World of Warcraft [CLASSIC] the Eye of Eternity [EOE] P1-P2
World of Warcraft [CLASSIC] the Eye of Eternity [EOE] 永恒之眼(蓝龙) 第一阶段 第二阶段 第三阶段 载具1-6技能介绍 World of Warcraft [CLASSIC] the Eye of Eternity [EOE]_永恒之眼 eoe-CSDN博客 永恒之眼怎么出副本呢,战斗结束&am…...
一键翻译全球:多语言支持下的英文翻译工具
随着科技的飞速发展,一系列英文翻译工具应运而生,它们以人工智能为驱动,极大地简化了跨语言交流的过程。本文将带您一窥英文翻译工具探索那些能够帮助我们跨越语言鸿沟的神奇工具。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.c…...
水战再起波澜,“怡宝”要下好怎样一盘棋?
不少投资者常把那些刚需性强、永远也不可能淘汰的产业称为“日不落产业”,从细分板块来看,水无疑具有一定代表性。农夫山泉掌门人钟晱晱曾直言:“我选择了一个日不落的产业,你永远要喝水,不可能不喝水。” 多年下来&a…...
使用maven快速生成打包文件3
这里再介绍一种打包方式,依赖包分开打包,直接将需要部署的文件打包成一个要锁文件,比如kafka-roma-bin.tar.gz,这里需要两个文件,一个pom2.xml,一个package.xml。 pom2.xml <?xml version"1.0&q…...
Excel技巧(一)
快捷键技巧 原文链接 选取某一行的数据直到最后一行:【CTRL SHIFT ↓ 】或者选取一行后按住SHIFT键,双击下边线就可以快速选取区域。 如果表格中有多行空行,可以先按CTRL SHIFT END,再按CTRL SHIFT 上下键调整,…...
C语言:文件复制
文本文件复制: #include<stdio.h>int main() {FILE* pFile1 NULL;FILE* pFile2 NULL;fopen_s(&pFile1,"D:\\11111.txt","r");fopen_s(&pFile2,"D:\\222.txt", "w");char c;while((cfgetc(pFile1))!EOF){f…...
谈谈建筑项目管理:类型、流程和工具
无论是在材料采购还是供应商管理方面,确保建筑项目按计划进行并控制在预算内始终是一项挑战。 如今,建筑项目管理正逐步采用软件驱动的方法来提升其效率。这一转型显著优化了项目规划、调度和资源配置,使建筑管理更加精确和高效。 什么是建…...
【Vue】生命周期函数
系列文章目录 第五章 生命周期函数 文章目录 系列文章目录 生命周期函数代表的是Vue实例,或者是Vue组件,在网页中各个生命阶段所执行的函数。生命周期函数可以分为创建阶段、挂载阶段、更新阶段以及卸载阶段。 创建阶段:setup挂载阶段&…...
C++系列-文件操作
文件操作 文件类型文本文件二进制文件 文件操作的三大类文件的打开方式ios::app(append)和 ios::ate(at end) 写文件写文件文件步骤读文件文件步骤二进制文件读写写一般数据写特殊数据 程序运行时产生的数据都属于临时数据,一旦程序运行完毕,就会释放&am…...
ES6解构赋值详解;全面掌握:JavaScript解构赋值的终极指南
目录 全面掌握:JavaScript解构赋值的终极指南 一、数组解构赋值 1、基本用法 2、跳过元素 3、剩余元素 4、默认值 二、对象解构赋值 1、基本用法 2、变量重命名 3、默认值 4、嵌套解构 三、复杂的嵌套结构解构 四、函数参数解构赋值 1、对象解构作为函…...
2-73 基于matlab的weber能量法求解齿轮时变啮合刚度的程序
基于matlab的weber能量法求解齿轮时变啮合刚度的程序,能够跑出刚度图,通过求解轮齿部分变形、基体变形及局部接触变形这三部分的变形,进而求得综合弹性变形,最终求出时变啮合刚度。程序已调通,可直接运行。 2- 73 齿轮…...
[C++]set和map的介绍及使用
关于set和map的接口函数部分,只重点介绍一些相较于别的容器有特殊地方的接口,set和map的接口可以触类旁通。 一、概念 (一)、关联式容器 关联式容器存储的元素是一个个的键值对<key,value>。通过键(key&#x…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
