发布时间:2026/7/15 2:58:40
零基础小白在学习链表(LinkedList)的思考 带你拆解底层逻辑 在数据结构中我们知道顺序表虽然尾插的时间复杂度O(1),但其无论是中间/头部的插⼊删除时间复杂度O(N)),还是增容时所面临空间的消耗都不可忽视思考我们当如何解决以上问题呢一、什么是链表其与数组的区别是什么1、链表一种物理上不连续但数据元素的逻辑顺序通过链表中指针次序所链接的存储结构2、其与数组的区别对比维度数组顺序表单链表无尾指针内存存储物理内存连续内存碎片化、不连续访问方式支持arr[i] 直接取O(1)不支持必须从头遍历O(n)头部插入/删除O(n)所有元素后移O(1)仅修改指针指向尾部插入均摊O(1)偶尔扩容拷贝O(n)每次要遍历到末尾中间插入/删除O(n)后续元素整体移位O(n)需要先找到目标位置空间开销仅存储数据额外开销小每个节点多存1个next指针额外内存开销大容量大小固定/动态扩容扩容有性能损耗无固定上限按需申请节点无需扩容3、链表结构(以单链表SLT [Single Linked Table]为例#includestdio.h#includestdlib.h// 1. 定义节点结构体structSLTNode{intdata;structSLTNode*next;};// 2. 给结构体起别名typedefstructSLTNodeNode;// 3. 给结构体指针起别名简化代码typedefstructSLTNode*PNode;采用struct关键字定义链表节点结构体节点分为两部分数据域 int data用于存储链表需要保存的数据可按需更换数据类型指针域 struct SListNode* next一级结构体指针存储下一个相邻节点的内存地址通过地址串联所有节点形成链式结构。使用typedef对结构体及结构体指针重命名Node等价于 struct SLTNode代表单个节点实体PNode等价于 struct SLTNode*代表节点指针简化链表操作代码书写。单链表逻辑特征节点内存不连续仅依靠next指针维系前后节点关系尾部节点next指针置NULL代表链表结束。二、链表的基本功能代码实现1、工具函数新建节点PNodeBuyNode(intx){PNode newNode(PNode)malloc(sizeof(Node));if(newNodeNULL){perror(malloc failed);exit(-1);}newNode-datax;newNode-nextNULL;returnnewNode;}malloc动态开辟内存初始化数据next 置空所有插入操作都会复用这个函数注意事项这里的newNode的类型是一级指针PNode即newNode存有对应节点的地址其指向一个节点2、打印链表遍历查看数据调试必备voidSLTPrint(PNode phead){PNode curphead-next;//跳过哨兵头节点while(cur!NULL){printf(%d - ,cur-data);curcur-next;}printf(NULL\n);}这里phead是一个不存有数据的指针(哨兵头节点)通过phead-next找到链表中第一个存有数据的有效节点通过cur指针不断将节点的数据打印而出并且将cur不断赋值成其所指向的下一节点的指针直至cur变为空指针 打印截止3、头插在链表最前面插入数据voidSLTPushFront(Node**pphead,LinkData x){Node*newnodeBuyNode(x);newnode-next*pphead;*ppheadnewnode;}错误写法// 错误写法无法修改外部头指针voidSLTPushFront(Node*phead,LinkData x){Node*newnodeBuyNode(x);newnode-nextphead;pheadnewnode;// 只修改函数内局部副本外部原指针完全不变}C 语言函数传参属于值拷贝传递如果头插函数仅使用一级指针Node* phead作形参当head为空指针时调用函数headNULL的值被拷贝到形参phead中此时phead也是NULL此时虽然他们的值都是NULL,但地址却是不一样的比如下方中的phead值为NULL 存有地址0x0003 自己地址为0x0002传入后会出现新的phead值NULL 存有地址0x0003但其地址可能时0x00A34、尾插在链表末尾插入数据(原理与3差不多) ps这里的ptail为为了找到原链表的尾节点不直接用*pphead为了便于寻找的同时不改动头节点voidSLTPushBack(Node**pphead,LinkData x){Node*newnodeBuyNode(x);Node*ptail*pphead;if(*ppheadNULL){*ppheadnewnode;}else{while(ptail-next){ptailptail-next;}ptail-nextnewnode;}}5、其余本质上实现原理与之前一致这里简要概述// 头删voidSLTPopFront(Node**pphead);// 尾删voidSLTPopBack(Node**pphead);// 按值查找节点Node*SLTFind(Node*phead,LinkData x);// 在pos节点前插入数据voidSLTInsert(Node**pphead,LinkData x,Node*pos);// 在pos节点后插入数据voidSLTInsertAfter(Node*pos,LinkData x);// 释放整条链表并置空头指针voidSLTDestroy(Node**pphead);各功能实现与简短说明5.1. 头删 SLTPopFrontvoidSLTPopFront(Node**pphead){Node*del*pphead;*ppheaddel-next;free(del);}说明可能修改头指针使用二级指针直接更新表头并释放原首节点。5.2. 尾删 SLTPopBackvoidSLTPopBack(Node**pphead){// 链表仅有一个节点if((*pphead)-nextNULL){free(*pphead);*ppheadNULL;return;}// 找到倒数第二个节点Node*cur*pphead;while(cur-next-next)curcur-next;free(cur-next);cur-nextNULL;}说明链表只剩单个节点时需要置空头指针必须二级指针。5.3. 查找 SLTFindNode*SLTFind(Node*phead,LinkData x){Node*curphead;while(cur){if(cur-datax)returncur;curcur-next;}returnNULL;}说明仅遍历读取数据不修改表头一级指针即可。5.4. 指定节点前插入 SLTInsertvoidSLTInsert(Node**pphead,LinkData x,Node*pos){Node*newnodeBuyNode(x);// 插入位置为头部更新表头if(*ppheadpos){newnode-next*pphead;*ppheadnewnode;return;}// 寻找 pos 的前驱节点Node*cur*pphead;while(cur-next!pos)curcur-next;cur-nextnewnode;newnode-nextpos;}说明若 pos 是头节点会改变链表头部使用二级指针。5.5. 指定节点后插入 SLTInsertAftervoidSLTInsertAfter(Node*pos,LinkData x){Node*newnodeBuyNode(x);newnode-nextpos-next;pos-nextnewnode;}说明永远不会改动链表头部仅修改节点内部 next一级指针够用。5.6. 销毁链表 SLTDestroyvoidSLTDestroy(Node**pphead){assert(pphead);Node*cur*pphead;while(cur){Node*nextcur-next;free(cur);curnext;}// 外部头指针置空防止野指针*ppheadNULL;}说明销毁后需要清空外部头指针变量必须二级指针。总结需要修改外部头指针头删、尾删、pos 前插、销毁链表 → 参数 Node**仅遍历 / 后置插入不改动表头查找、pos 后插 → 参数 Node*二级指针核心逻辑C 语言值传递只有传入指针变量的地址才能修改外部原始指针。

相关新闻

2026/7/15 2:58:40

静态NAT、动态NAT与PAT:从原理到实战配置的深度解析

1. NAT技术基础:从地址枯竭到网络桥梁想象一下你住在一个小区里,每家每户都有内部房间号(比如A栋101),但对外只用一个统一的小区地址。当快递员送货时,物业负责把包裹从小区大门转送到具体住户——这就是NA…

2026/7/15 2:53:40

魔芋 AI:全球大模型一站式调用效果实测

在开发智能应用时,最让人头疼的往往不是算法逻辑本身,而是如何稳定、高效地连接到合适的大模型。很多开发者都经历过这样的场景:本地测试一切正常,一旦上线就面临接口超时、密钥管理混乱、不同模型切换成本高昂等问题。尤其是当业…

2026/7/15 7:44:33

ROS2 Bag录制原理与工程实践:从调试诊断到数据资产管理

1. 项目概述:为什么“把节点数据录进包”是ROS2开发绕不开的第一课在ROS2实际开发中,我见过太多人卡在同一个地方:写好了发布者节点,也搭好了订阅者逻辑,但一到调试阶段就抓瞎——消息到底发没发?时间戳对不…

2026/7/15 7:44:33

基于MATLAB/Simulink的无刷直流电机双闭环调速系统建模与仿真实践

1. 无刷直流电机双闭环调速系统基础无刷直流电机(BLDC)作为现代工业中的核心动力元件,凭借其高效率、长寿命和低维护成本等优势,在机器人、电动汽车和工业自动化等领域广泛应用。与传统有刷电机相比,它通过电子换向取代…

2026/7/15 7:44:33

深入解析TI DS90UB962-Q1 FPD-Link III解串器的I2C控制与中断机制

1. 项目概述在汽车电子,尤其是高级驾驶辅助系统(ADAS)和多摄像头环视系统中,如何高效、可靠地管理连接在长距离串行链路上的多个传感器,是一个核心挑战。TI的DS90UB962-Q1四路FPD-Link III解串器,正是为此类…

2026/7/15 7:44:33

Vivado时序仿真中时钟偏斜与门延时的实战影响分析

1. Vivado时序仿真的核心挑战在FPGA开发中,功能仿真通过后的设计往往会在时序仿真阶段暴露出意料之外的问题。我曾遇到过这样一个案例:一个简单的组合逻辑选择器在功能仿真中表现完美,但在后仿真时却出现了输出异常。通过波形分析发现&#x…

2026/7/14 12:47:32

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/14 19:23:19

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/14 18:30:06

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/15 0:08:29

【LINUX】驱动

【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】

2026/7/15 0:08:29

【1982-2026】全国高精度建筑轮廓|村级精度|SHP矢量

🔍 数据简介 本次分享1982-2026年全国村级精度建筑轮廓矢量数据,覆盖全国各省市区县,到村级别精细,为2026年最新实时采集成果,非网传仅60/77个城市的老旧数据。 数据含带高度/不带高度双版本,单体建筑边界精…

2026/7/15 0:08:29

【1975-2026】全国水系水路数据|河流/水库/运河|SHP矢量

🔍 数据简介 本次分享1975-2026年全国高精度水系水路矢量数据,覆盖全国全域,包含河流、水系、水库、运河、湿地、冰川、沟渠等全类别水文要素。 数据集包含双层矢量图层,字段分类清晰、要素齐全,支持2013-2026逐年完整…

2026/7/14 12:47:31

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…