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

文章目录

  • 什么是链表(链表概念及分类)
    • 链表分类
    • 单链表和双链表的区别
  • ‍♂️单链表、双向链表的实现
    • 单链表的实现
    • 双向链表的实现
  • 链表经典OJ笔试题
    • 反转单链表
    • 移除链表元素
    • 合并两个有序链表
    • 链表分割
    • 链表的中间结点
    • 环形链表
      • 环形链表 I:判断链表中是否有环
      • 环形链表 II:判断链表开始入环的第一个结点
    • 复制带随机指针的链表
  • 链表相关文章直通车

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

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

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

链表分类

无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
链表(基础详解、实现、OJ笔试题)_第1张图片
单链表的每个节点分为两部分,一部分存储数据,一部分存储下一个节点的地址。前一个节点中存储着下一个节点的地址,这也是单链表能连起来的原因。
带头双向循环链表:结构最复杂,但结构最优,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。
链表(基础详解、实现、OJ笔试题)_第2张图片
双向链表的节点有两个指针域和一个数据域,两个指针一个指向后一个节点,另一个指向前一个节点,数据域中存储数据。默认双向链表都是有带哨兵位的头节点,哨兵位的头节点中储存着第一个有效节点的地址(phead->next)和最后一个有效节点的地址(phead->prev)。 除了上面两个最常用的链表之外,还有无头单向循环链表、带头单向循环链表、带头单向不循环链表、无头双向循环链表等等,总之可以将是否带头、是否循环、单双向这三个条件排列组合,另外还会有一些另类的复杂列表,文末会举出例子。

单链表和双链表的区别

单链表的指针域中只有一个地址,指向的是下一个结点的地址。而双链表的指针域中有两个地址:前一个结点的地址和后一个结点的地址。
单链表找尾结点比较麻烦,需要遍历;而双链表找尾结点只需要找头结点的上一个结点即可。
单链表只要一直往后遍历就会遇到空指针结束,而双向链表则可能会难以控制循环结束的条件而死循环下去。
单链表中一般默认没有哨兵位的头结点;而双链表中默认头结点,里面存的是最后一个结点和第一个有效结点的地址。

逻辑图对比
链表(基础详解、实现、OJ笔试题)_第3张图片
物理图对比
链表(基础详解、实现、OJ笔试题)_第4张图片

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

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

单链表的实现

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

双向链表的实现

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

链表经典OJ笔试题

反转单链表

链表(基础详解、实现、OJ笔试题)_第5张图片
思路是用三个指针,从前到后一次改变每个结点的指向。
题目及详解:反转单链表

移除链表元素

链表(基础详解、实现、OJ笔试题)_第6张图片
定义两个指针,保证从第二个结点开始,一个指针在另一个指针的后面,这样就能在不丢失数据的情况下移除链表某结点。
题目及详解:移除链表元素

合并两个有序链表

链表(基础详解、实现、OJ笔试题)_第7张图片
将两个链表的节点逐个比较,小的尾插到新链表的后面,每次尾插完,新链表和较小值的链表的指针都要向前走,有一个为空就停止循环,最后再将那个不为空的链表节点全部尾插到新链表。
链表(基础详解、实现、OJ笔试题)_第8张图片
这道题最好的思路是构建一个哨兵位来实现尾插,不构建哨兵位也可以,但需要考虑更多的边界条件。
题目及详解:合并两个有序链表

链表分割

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
如图,给定的链表为 4-5-3-1-2-7 ,给一定值为 3,分割后的值为 1-2-4-5-3-7
链表(基础详解、实现、OJ笔试题)_第9张图片
此题最好的解决方法是开辟两个哨兵位的头结点,将这两两部分的数据按要求一次尾插到两个哨兵位的后面,再将较小的一部分的尾结点指向较大部分的第一个结点,将较大部分的最后一个结点置空,最后将两个哨兵位释放,返回较小部分的第一个结点的地址即可。
题目及详解:链表分割

链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
此题知识点:快慢指针
控制两个指针,快指针每次向前走两步步,慢指针每次向前走一步,当快指针走到尾部的时候,慢指针则刚好走到中间结点。
题目及详解:链表的中间结点

环形链表

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

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

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

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

复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点。
链表(基础详解、实现、OJ笔试题)_第10张图片
复制后的链表相关位置的索引必须和原链表一模一样。
题目思路

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

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

链表相关文章直通车

单链表的实现
双链表的实现
反转单链表
移除链表元素
合并两个有序链表
链表分割
链表的中间结点
环形链表
复制带随机指针的链表

你可能感兴趣的:(数据结构与算法,学习,链表,数据结构)