快速上手 C++ 数据结构与算法
王健伟
《C++ 新经典》系列作者,资深 C++ 讲师
3224 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
结束语 (1讲)
快速上手 C++ 数据结构与算法
15
15
1.0x
00:00/00:00
登录|注册

05|双链表:搜索链表中节点的速度还可以更快吗?

你好,我是王健伟。
上节课,我们学习了单链表的相关操作,我们会用它来对数据进行顺序存储,如果需要频繁增加和删除数据,同样也可以用到单链表。而它也可以衍生出好多种链表结构,双链表(也称双向链表)就是其中一种。
在单链表中,有一个指针域用于指向后继节点。这带来的问题是,如果要寻找单链表中某个已知节点的前趋节点,就会比较繁琐了,我们必须从链表头出发开始寻找,算法的平均情况时间复杂度为 O(n)。
那要怎么解决这个问题呢?
在单链表的基础上,我们可以增加一个用于指向前趋节点的指针,也称为前趋指针,当然,第一个节点的前趋指针指向 nullptr,如果是带头节点的链表,那么就是头节点的前趋指针指向 nullptr。这样,当查找某个节点的前趋节点就会非常容易,查找算法的时间复杂度也会从 O(n) 变为 O(1)。
这种增加了前趋指针的链表,被称为双链表。如果画得形象一点,双链表(带头节点)数据存储的描述图应该如图 9 所示:
图9  带头节点的双链表数据存储描述图
双链表的很多操作和单链表相同,比如元素获取、求长度、判断是否为空、链表释放等操作,因为这些操作并不需要用到前趋指针。而有一些常用操作双链表与单链表不同,下面,我还是使用带头结点的代码实现方式,来实现双向链表。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

双链表是一种链表结构,相较于单链表,它引入了前趋指针,使得查找某个节点的前趋节点更加高效。本文通过简洁清晰的代码示例和图示,帮助读者快速了解双链表的结构和操作,为进一步深入学习和应用提供了基础。另外,文章还提到了双链表的翻转操作,鼓励读者通过参考单链表的翻转操作,对比两者的不同来独立完成双链表的翻转操作。双链表的特点包括寻找前趋节点的时间复杂度为O(1),存放前趋指针需要额外消耗存储空间,以及利用head指针和last指针进行节点查找的优势。通过本文的讲解,读者还可以对C++标准模板库中的list容器的工作原理以及优缺点有了非常清晰的认识。整体而言,本文通过对比单链表和双链表的操作,帮助读者更好地理解双链表的特点和优势。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《快速上手 C++ 数据结构与算法》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(4)

  • 最新
  • 精选
  • 雪无痕
    p->prior->next = p->net->prior = p,这里p->net应为p->next

    作者回复: 感谢支持,麻烦编辑同学修正

    2023-06-15归属地:北京
  • Bruder_Jin
    vector容器和list容器有以下区别: (1)vector内存连续,list内存不连续 (2)vector会预分配内存,capacity为vector实际内存大小,list内存分配为实际数据大小 (3)vector内存达到capacity容量时将vector数组全部拷贝到新的capacity大小的内存区域,会比list多进行内存拷贝 (4)vector实现对应数组,因此可以直接下标访问vector[i],而list容器内存不连续因此无法下标访问;因此数据涉及大量的随机访问(读操作)则最好使用vector (5)vector插入删除中间元素时数组会整体移动,而list插入删除直接修改链表指针;因此高效插入删除时还是list好些

    作者回复: 挺好的呦

    2023-06-05归属地:广东
  • Geek_7ba740
    可以理解为读多写少用vector,写多读少用list,不确定的话用vector吗

    作者回复: 可以这么理解。👶

    2023-04-08归属地:四川
  • 铁甲依然在
    我写了双链表的反转代码 //双链表的链表反转 template<typename T> void DbLinkList<T>::ReverseList() { if (m_length < 1) { return; } DblNode<T>* pothersjd = m_head->next->next; //指向从第二个节点的后续节点 m_head->next->next = nullptr; //第一个节点的后续指点指针值为空 DblNode<T>* ptemp; while (pothersjd != nullptr) { ptemp = pothersjd; //临时节点 pothersjd = pothersjd->next; //第二节点后移动 ptemp->prior = m_head; //后一段节点的前驱节点值为头节点 ptemp->next = m_head->next; //后一段节点的后驱节点为头节点的后驱节点 m_head->next->prior = ptemp; //头节点前的前一段节点的前驱节点为新插入的节点 m_head->next = ptemp; //头节点的后驱节点为新插入的节点 } }
    2023-10-10归属地:广东
收起评论
显示
设置
留言
4
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部