业务开发算法 50 讲
黄清昊
Hashdata 数据库内核工程师,LeetCode 高赞答主,公众号微扰理论作者
23292 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
业务开发算法 50 讲
15
15
1.0x
00:00/00:00
登录|注册

02|双向链表:list如何实现高效地插入与删除?

pop_front/pop_back/push_back
删除节点
插入节点
初始化
时间复杂度
实现find方法
链表基本操作
链表数据结构
链表迭代器
链表节点
双向、循环链表
指针变换顺序
遍历、插入、删除操作较多
查询索引较少
低插入、删除复杂度
灵活性
课后作业
STL中List的实现
实现注意点
适用场景
优点
链表

该思维导图由 AI 生成,仅供参考

你好,我是微扰君。
在上一讲实现的一个简易银行账户管理系统中,每个账号都对应了一个余额,系统支持用户的开通、存 / 取款和查询余额。我们使用动态数组容器满足了频繁随机访问查询的需求。
但是如果要在系统里支持删除的功能,就会有一个问题:我们为了不进行整体的数组移动操作,通常就只能保留这个用户在数组里占用的内存,用将元素标记为特殊值的方式来模拟“删除”;而因为数组是连续存储的,不能单独释放掉数组中间某些区域的内存,所以这段内存空间我们实际上就是浪费的。
如果还有个需求,比如现在某个不讲道理的领导来到这个银行,要求自己在数组中排在最前面;那么我们不得不将所有人的账户信息往后挪动一位来满足他奇怪的自尊心,这也会带来高昂的时间复杂度。
那么有没有办法让我们不再需要连续的存储空间去存储一个序列,同时又可以在序列中快速进行插入 / 删除操作而不用波及之后的所有元素呢?
这就需要另一种常见的序列式数据结构——链表登场了,这同样是几乎所有高级语言都会原生支持的数据结构。

链表

链表这个数据结构的发明也是很久之前的事了,最早在 1955 年,它就是 IPL 这一古老语言的内置数据结构,用于开发当时的人工智能程序。
类似数组,链表同样是一种序列式的数据结构,但存储元素时并不需要使用连续的内存空间,而是采用一系列通过指针相连的节点来存储,因为有了指针来关联节点的地址,就不需要连续存储了
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

链表是一种常见的序列式数据结构,与数组不同,它通过指针相连的节点来实现非连续的存储。这种特性使得链表在插入和删除操作上高效,但在随机访问索引上效率较低。文章介绍了单链表、双链表和循环链表的区别,以及STL中List的实现。通过对链表节点和迭代器的实现,读者可以了解链表的基本概念和实现方式。链表适用于删除、插入、遍历操作频繁的场景,比如内存池、操作系统进程管理和缓存替换算法LRU等。文章内容深入浅出,适合读者快速了解链表的特点和应用场景。文章还详细介绍了链表的初始化、插入和删除操作的实现方式,以及相关的基础操作。通过对这些操作的实现,读者可以更好地理解链表的灵活性和高效性。总的来说,链表相比数组具有更好的灵活性和更低的插入、删除复杂度,适用于查询索引较少、遍历、插入、删除操作较多的场景。链表操作在实现过程中需要注意指针之间的变换顺序,这也是面试官在算法面试中经常会考察的点。文章内容丰富,对于想要深入了解链表的读者来说是一份很好的资料。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《业务开发算法 50 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(6)

  • 最新
  • 精选
  • Paul Shan
    链表放弃了数组规整连续的布局,只存储下一个或者上一个节点指针,带来了插入和删除的高效,也充分利用了内存的碎片,但是牺牲了全局查询的效率。

    作者回复: 说的很好

    2021-12-14
    7
  • webmin
    数组是一种特殊形式的链表,把链接任意跳转压缩为游标定位。

    作者回复: 我觉得这个和链表还是有本质区别的哈; 数组基于元素下表访问数据可以做到O(1)是因为可以直接计算出元素在内存中的地址;而链表只能通过遍历实现这一点。

    2021-12-14
    3
    2
  • vcjmhg
    最容易想到的方法就是从起点调用迭代器进行遍历,遍历过程中比较节点值与3是否相同,如果相同则返回该位置迭代器,否则继续向后遍历;时间复杂度为O(n),如果链表本身有序,可考虑进行优化,比如用红黑树,时间复杂度可降低至O(logn)。

    作者回复: 没错 红黑树我们之后也会展开讲解 可以+V: constant_variation 一起交流~

    2021-12-17
  • 是O(n),但如果一个链表要保证有序 那么我可以在find之后保存一下上次find的指针位置 然后下次find决定往前或者往后 不过这是一个简单的思考 怎么折腾都是O(N)

    作者回复: 嗯嗯 不过链表本身要有序是一个很高的要求哈 这种时候一般会采用红黑树或者跳表实现

    2021-12-14
    2
  • 那时刻
    begin() 则会指向虚拟节点的下一个节点,这完美符合迭代器前开后闭的语义。 这里貌似应该是前闭后开?

    作者回复: 你说的没错 感谢指证

    2021-12-14
  • 新世界
    第一处代码位置,前驱节点和后继节点注释写反了
    2022-02-11
    2
收起评论
显示
设置
留言
6
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部