链表(基础详解、实现、OJ笔试题)

简介: 链表(基础详解、实现、OJ笔试题)



大家好,我是纪宁。

这篇文章将带来完整版的链表内容的讲解。文章内容包括链表的概念、分类、单双链表的实现、链表的经典OJ题目等。每一个专题中讲解了相应问题实现思路及方法,当然,实际解决过程中肯定也会出现各种各样的小问题,记录每个问题具体实现方法和代码的文章链表在每个专题的末尾,点击即可进入。其次,文章末尾也提供了上述所有问题链接的合集,供大家前往参考学习。

🧚什么是链表(链表概念及分类)

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。非连续的意思就是链表的每一部分可以在内存的任意一块区域存在,且这块区域的地址是随机的,所以一般用动态内存来开辟这块空间的地址。而链表的每一部分都称为一个节点,每个节点分为两部分:数据域和指针域,通过指针域即可访问其他结点的数据。

链表分类

无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

单链表的每个节点分为两部分,一部分存储数据,一部分存储下一个节点的地址。前一个节点中存储着下一个节点的地址,这也是单链表能连起来的原因。

带头双向循环链表:结构最复杂,但结构最优,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。

双向链表的节点有两个指针域和一个数据域,两个指针一个指向后一个节点,另一个指向前一个节点,数据域中存储数据。默认双向链表都是有带哨兵位的头节点,哨兵位的头节点中储存着第一个有效节点的地址(phead->next)和最后一个有效节点的地址(phead->prev)。 除了上面两个最常用的链表之外,还有无头单向循环链表、带头单向循环链表、带头单向不循环链表、无头双向循环链表等等,总之可以将是否带头、是否循环、单双向这三个条件排列组合,另外还会有一些另类的复杂列表,文末会举出例子。

单链表和双链表的区别

单链表的指针域中只有一个地址,指向的是下一个结点的地址。而双链表的指针域中有两个地址:前一个结点的地址和后一个结点的地址。

单链表找尾结点比较麻烦,需要遍历;而双链表找尾结点只需要找头结点的上一个结点即可。

单链表只要一直往后遍历就会遇到空指针结束,而双向链表则可能会难以控制循环结束的条件而死循环下去。

单链表中一般默认没有哨兵位的头结点;而双链表中默认头结点,里面存的是最后一个结点和第一个有效结点的地址。

逻辑图对比

物理图对比

🚴‍♂️单链表、双向链表的实现

将链表中的数据类型重定义为某种类型,并定义一个链表节点的结构体,其中节点的数据域是当前节点的数据,另一部分则是地址。即将链表的数据域和指针域放在一个结构体中,且链表中存储的数据最好是可变的,每生成一个链表都要单独开辟额外的空间。

单链表的实现

每开辟一个结点的空间,都要为这个结点的数据域赋值,并让它的指针域指向NULL。单链表的头插头删都要传二级指针,因为要改变头插头删都要改变头指针的指向,删除某一结点,需要先找到这个结点的上一个结点,必要时候要用另一个结点保存某个结点的地址,防止地址丢失的情况。

具体实现方式:单链表的实现

双向链表的实现

双向链表在开辟结点时,要先将结点的指针域置空,当确定结点位置时,再将结点的两个指针域指向应指向的结点。

具体实现方式:双链表的实现

🍉链表经典OJ笔试题

反转单链表

思路是用三个指针,从前到后一次改变每个结点的指向。

题目及详解反转单链表

移除链表元素

定义两个指针,保证从第二个结点开始,一个指针在另一个指针的后面,这样就能在不丢失数据的情况下移除链表某结点。

题目及详解移除链表元素

合并两个有序链表

将两个链表的节点逐个比较,小的尾插到新链表的后面,每次尾插完,新链表和较小值的链表的指针都要向前走,有一个为空就停止循环,最后再将那个不为空的链表节点全部尾插到新链表。

这道题最好的思路是构建一个哨兵位来实现尾插,不构建哨兵位也可以,但需要考虑更多的边界条件。

题目及详解合并两个有序链表

链表分割

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

如图,给定的链表为 4-5-3-1-2-7 ,给一定值为 3,分割后的值为 1-2-4-5-3-7

此题最好的解决方法是开辟两个哨兵位的头结点,将这两两部分的数据按要求一次尾插到两个哨兵位的后面,再将较小的一部分的尾结点指向较大部分的第一个结点,将较大部分的最后一个结点置空,最后将两个哨兵位释放,返回较小部分的第一个结点的地址即可。

题目及详解:链表分割

链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

此题知识点:快慢指针

控制两个指针,快指针每次向前走两步步,慢指针每次向前走一步,当快指针走到尾部的时候,慢指针则刚好走到中间结点。

题目及详解:链表的中间结点

环形链表

环形链表中用到了快慢指针和追及问题相关知识带点。

环形链表 I:判断链表中是否有环

环形链表 II:判断链表开始入环的第一个结点

环形链表I、II 题目及详解环形链表

复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点。

复制后的链表相关位置的索引必须和原链表一模一样。

题目思路

  • 拷贝所有节点,,每个结点放在对应原节点的后面。
  • 将每个 random 指向对应的位置。
  • 将复制的链表解下来,尾插到一起,并将原链表恢复。

题目及详解复制带随机指针的链表

相关文章
|
1月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
24 7
|
4月前
【数据结构OJ题】环形链表
力扣题目——环形链表
36 3
【数据结构OJ题】环形链表
|
4月前
【数据结构OJ题】复制带随机指针的链表
力扣题目——复制带随机指针的链表
51 1
【数据结构OJ题】复制带随机指针的链表
|
4月前
【数据结构OJ题】环形链表II
力扣题目——环形链表II
29 1
【数据结构OJ题】环形链表II
|
4月前
【数据结构OJ题】相交链表
力扣题目——相交链表
32 1
【数据结构OJ题】相交链表
|
4月前
【数据结构OJ题】合并两个有序链表
力扣题目——合并两个有序链表
39 8
【数据结构OJ题】合并两个有序链表
|
4月前
【数据结构OJ题】移除链表元素
力扣题目——移除链表元素
40 2
【数据结构OJ题】移除链表元素
|
4月前
【数据结构OJ题】链表中倒数第k个结点
牛客题目——链表中倒数第k个结点
32 1
【数据结构OJ题】链表中倒数第k个结点
|
4月前
【数据结构OJ题】链表分割
牛客题目——链表分割
29 0
【数据结构OJ题】链表分割
|
4月前
【数据结构OJ题】链表的回文结构
牛客题目——链表的回文结构
36 0
【数据结构OJ题】链表的回文结构