链表(链式存储)基本原理

简介: 链表是一种通过指针串联节点的线性结构,无需连续内存,支持高效增删。单链表仅有next指针,双链表增加prev指针以支持双向遍历。相比数组,链表插入删除灵活,无扩容负担,但不支持随机访问,查找需从头遍历。实际开发中常用双链表,配合虚拟头结点简化操作。

链表(链式存储)基本原理
刷过力扣的读者肯定对单链表非常熟悉,力扣上的单链表节点定义如下:
这仅仅是一个最简单的单链表节点,方便力扣出算法题来考你。在实际的编程语言中,我们使用的链表节点会稍微复杂一点,类似这样:
主要区别有两个:
1、编程语言标准库一般都会提供泛型,即你可以指定 val 字段为任意类型,而力扣的单链表节点的 val 字段只有 int 类型。
2、编程语言标准库一般使用的都是双链表而非单链表。单链表节点只有一个 next 指针,指向下一个节点;而双链表节点有两个指针,prev 指向前一个节点,next 指向下一个节点。
有了 prev 前驱指针,链表支持双向遍历,但由于要多维护一个指针,增删查改时会稍微复杂一些,后面带大家实现双链表时会具体介绍。
为什么需要链表
前面介绍了 数组(顺序存储)的底层原理,说白了就是一块连续的内存空间,有了这块内存空间的首地址,就能直接通过索引计算出任意位置的元素地址。
链表不一样,一条链表并不需要一整块连续的内存空间存储元素。链表的元素可以分散在内存空间的天涯海角,通过每个节点上的 next, prev 指针,将零散的内存块串联起来形成一个链式结构。
这样做的好处很明显,首先就是可以提高内存的利用效率,链表的节点不需要挨在一起,给点内存 new 出来一个节点就能用,操作系统会觉得这娃好养活。
另外一个好处,它的节点要用的时候就能接上,不用的时候拆掉就行了,从来不需要考虑扩缩容和数据搬移的问题,理论上讲,链表是没有容量限制的(除非把所有内存都占满,这不太可能)。
当然,不可能只有好处没有局限性。数组最大的优势是支持通过索引快速访问元素,而链表就不支持。
这个不难理解吧,因为元素并不是紧挨着的,所以如果你想要访问第 3 个链表元素,你就只能从头结点开始往顺着 next 指针往后找,直到找到第 3 个节点才行。
上面是对链表这种数据结构的基本介绍,接下来我们就结合代码实现单/双链表的几个基本操作。
单链表的基本操作
如果觉得抽象,以下网站可以帮助完成:https://visualgo.net/zh/list
我先写一个工具函数,用于创建一条单链表,方便后面的讲解:
查/改
单链表的遍历/查找/修改
比方说,我想访问单链表的每一个节点,并打印其值,可以这样写:
类似的,如果是要通过索引访问或修改链表中的某个节点,也只能用 for 循环从头结点开始往后找,直到找到索引对应的节点,然后进行访问或修改。

在单链表头部插入新元素
直接看代码吧,很简单:
在单链表尾部插入新元素
这个操作稍微复杂一点,因为我们要先从头结点开始遍历到链表的最后一个节点,然后才能在最后一个节点后面再插入新节点:
当然,如果我们持有对链表尾节点的引用,那么在尾部插入新节点的操作就会变得非常简单,不用每次从头去遍历了。这个优化会在后面具体实现双链表时介绍
在单链表中间插入新元素
这个操作稍微有点复杂,我们还是要先找到要插入位置的前驱节点,然后操作前驱节点把新节点插入进去:

在单链表中删除一个节点
删除一个节点,首先要找到要被删除节点的前驱节点,然后把这个前驱节点的 next 指针指向被删除节点的下一个节点。这样就能把被删除节点从链表中摘除了
在单链表尾部删除元素
这个操作比较简单,找到倒数第二个节点,然后把它的 next 指针置为 null 就行了:
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});

// 删除尾节点
ListNode p = head;
// 找到倒数第二个节点
while (p.next.next != null) {
p = p.next;
}

// 此时 p 指向倒数第二个节点
// 把尾节点从链表中摘除
p.next = null;

// 现在链表变成了 1 -> 2 -> 3 -> 4
在单链表头部删除元素
这个操作比较简单,直接把 head 移动到下一个节点就行了,直接看代码吧:
Java
运行代码
复制代码
1
2
3
4
5
6
7
// 创建一条单链表
ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});

// 删除头结点
head = head.next;

// 现在链表变成了 2 -> 3 -> 4 -> 5
不过可能有读者疑惑,之前那个旧的头结点 1 的 next 指针依然指向着节点 2,这样会不会造成内存泄漏?不会的,这个节点 1 指向其他的节点是没关系的,只要保证没有其他引用指向这个节点 1,它就能被垃圾回收器回收掉。
当然,如果你非要显式把节点 1 的 next 指针置为 null,这是个很好的习惯,在其他场景中可能可以避免指针错乱的潜在问题。
😁是不是觉得复杂?
链表的增删查改操作确实比数组复杂。这是因为链表的节点不是紧挨着的,所以要增删一个节点,必须先找到它的前驱和后驱节点进行协同,然后才能通过指针操作把它插入或删除。
上面给出的代码还仅仅是最简单的例子,你会发现在头部、尾部、中间增删元素的代码都不一样。如果要实现一个真正可用的链表,你还要考虑到很多边界情况,比如链表可能为空、前后驱节点可能为空等,这些情况都得保证不出错。
而且,上面只是介绍了「单链表」,而我们下一章要实现的是「双链表」,双链表要同时维护前驱和后驱指针,指针操作会更复杂一些。
是不是已经不敢想了?不要怕,其实没你想的那么难,几个原因:
1、其实搞来搞去就那几个操作,等会儿带你动手实现链表 API 的时候,你亲自写一写,就会了。
2、最重要的,我们会使用「虚拟头结点」技巧,把头、尾、中部的操作统一起来,同时还能避免处理头尾指针为空情况的边界情况。

相关文章
|
12天前
|
机器学习/深度学习 人工智能 自然语言处理
构建AI智能体:三十八、告别“冷启动”:看大模型如何解决推荐系统的世纪难题
协同过滤是推荐系统中广泛使用的技术,其核心思想是利用用户行为数据发现相似用户或物品进行推荐。摘要包括:1)协同过滤基于用户历史行为数据,通过计算相似度(如余弦相似度、皮尔逊相关系数)预测用户偏好;2)主要分为基于用户(寻找相似用户群体)和基于物品(发现相似物品)两种方法;3)面临冷启动、数据稀疏性等挑战,可通过混合推荐(结合内容特征)和矩阵分解等技术解决;4)典型应用包括电商猜你喜欢和流媒体推荐;5)结合大语言模型可增强语义理解能力,提升推荐准确性。
211 9
|
19天前
|
前端开发 数据挖掘
精准类目+关键词布局,让1688商品快速获得曝光!
本文详解1688商品曝光提升策略,涵盖精准类目选择、关键词优化、流量获取及展现位竞争。通过科学布局关键词、完善商品信息、提升服务质量,助力商家精准触达客户,实现曝光与转化双增长。
|
15天前
|
人工智能 JSON 机器人
从零开始:用Python和Gemini 3四步搭建你自己的AI Agent
AI Agent并非玄学,核心仅为“循环 + 大模型 + 工具函数”。本文教你用Gemini 3从零搭建能读写文件、执行指令的命令行助手,拆解其“观察-思考-行动”循环机制,揭示智能体背后的简洁本质。
255 17
从零开始:用Python和Gemini 3四步搭建你自己的AI Agent
|
24天前
|
SQL 人工智能 自然语言处理
Apache Doris 4.0 版本正式发布:全面升级 AI 与搜索能力,强化离线计算
Apache Doris 4.0 正式发布!深度融合AI与搜索能力,支持向量索引、AI函数、全文检索打分,强化离线计算稳定性,提升查询性能与数据质量,助力企业构建高效实时数仓。
249 11
Apache Doris 4.0 版本正式发布:全面升级 AI 与搜索能力,强化离线计算
|
9天前
|
机器学习/深度学习 人工智能 运维
别只盯着 CPU 爆了!一篇文章带你看懂:从指标到根因的 AIOps 自动化故障定位流水线
别只盯着 CPU 爆了!一篇文章带你看懂:从指标到根因的 AIOps 自动化故障定位流水线
122 15
|
10天前
|
人工智能 自然语言处理
构建AI智能体:四十一、大模型思维链提示工程:技术原理与行业应用案例分析
本文介绍了思维链提示技术及其应用。思维链提示是一种引导大模型进行逐步推理的提示工程技术,通过结构化提示模拟人类解决问题的逻辑分析路径,使模型能够显式化中间推理步骤,从而提升推理准确性与可解释性。文章详细阐述了思维链提示的关键特征(步骤可解释性、逻辑链条完整性、问题分解能力)和工作原理,并通过数学推理、逻辑分析和多轮复杂问题三个案例展示了其具体应用流程。该技术在教育辅导、商业决策和科研分析等领域具有重要价值,能够突破传统大模型的黑箱推理瓶颈,提高AI系统的决策透明度和可靠性。
177 13
|
6天前
|
人工智能 自然语言处理 安全
AI 十大论文精讲(六):拆解 LLM 智能体的 “通用密码”
本文解读复旦NLP团队2023年重磅综述《The Rise and Potential of Large Language Model Based Agents》,系统剖析LLM智能体“大脑-感知-行动”三大核心模块,涵盖单智能体、多智能体、人机协作与智能体社群四大应用场景,提炼工具SKMA体系、安全护栏、结果检查三大落地要点,并提出AGI路径、虚拟到物理迁移等开放问题,为构建通用智能体提供统一范式,被誉为该领域“入门圣经”。
|
14天前
|
人工智能 UED 开发者
别把问卷做成"审讯录":用AI重构与用户的每一次对话
95%的用户调研问卷因为"审讯式提问"而被无视。本文提供一套基于认知心理学的AI指令,将枯燥的填表转化为有温度的对话,帮助开发者和产品经理设计出高完成率、高信度的调研问卷,打破"幸存者偏差",获取真实用户洞察。
110 9
|
25天前
|
JavaScript 算法 数据安全/隐私保护
解决Node.js错误:“error:0308010C:digital envelope routines::unsupported”
在应用上述解决方案前,请确保你的Node.js应用程序的所有依赖都是最新的,这可以通过运行 npm update来实现。同时,始终备份你的工作,以防需要回滚所做的任何更改。通过这些步骤,多数情况下应该能够解决"error:0308010C:digital envelope routines::unsupported"错误问题。这些解决方案能确保应用程序可以顺利运行,同时也为今后可能的OpenSSL库更新做好了准备。
213 16
|
25天前
|
人工智能 自然语言处理 算法
构建AI智能体:二十六、语言模型的“解码策略”:一文读懂AI文本生成的采样方法
本文探讨了AI文本生成中的采样方法,这些方法决定了AI如何选择候选词来生成文本。文章介绍了两种主要方法:确定性方法(贪心算法和束搜索)和随机采样方法(基础随机采样、温度采样、Top-k采样和Top-p采样)。贪心算法每次选择概率最高的词,生成结果可靠但缺乏创意;束搜索保留多条候选路径,适合需要准确性的任务。随机采样方法则通过引入随机性增加多样性,其中温度采样通过调整温度参数控制创意的随机程度,Top-p采样则动态选择候选词集合,是目前创造性任务的首选方法。
196 11