diff --git a/Contents/02.Linked-List/01.Linked-List-Basic/01.Linked-List-Basic.md b/Contents/02.Linked-List/01.Linked-List-Basic/01.Linked-List-Basic.md index 9a83d2e6..dfc59404 100644 --- a/Contents/02.Linked-List/01.Linked-List-Basic/01.Linked-List-Basic.md +++ b/Contents/02.Linked-List/01.Linked-List-Basic/01.Linked-List-Basic.md @@ -8,9 +8,9 @@ 以单链表为例,链表的存储方式如下图所示。 -![](https://qcdn.itcharge.cn/images/20211205151319.png) +![](https://qcdn.itcharge.cn/images/20211208180037.png) -如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的数据信息,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 `next`」。 +如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的值,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 `next`」。 在链表中,数据元素之间的逻辑关系是通过指针来间接反映的。逻辑上相邻的数据元素在物理地址上可能相邻,可也能不相邻。其在物理地址上的表现是随机的。 @@ -36,7 +36,7 @@ 从循环链表的任何一个节点出发都能找到任何其他节点。 -![](https://qcdn.itcharge.cn/images/20211208103712.png) +![](https://qcdn.itcharge.cn/images/20211208180048.png) 接下来我们以单链表为例,介绍一下链表的基本操作。 @@ -73,7 +73,7 @@ class LinkedList: - 每获取一个数据元素,就为该数据元素生成一个新节点,将新节点插入到链表的尾部。 - 插入完毕之后返回第 `1` 个链节点的地址。 -建立一个线性链表的时间复杂度为 $O(n)$,n 为线性表长度。 +建立一个线性链表的时间复杂度为 $O(n)$,`n` 为线性表长度。 **「建立一个线性链表」** 的代码如下: @@ -133,15 +133,15 @@ def find(self, val): ### 2.5 插入元素 -插入元素操作分为三种: +链表中插入元素操作分为三种: -- 头部插入元素:在链表第 `1` 个链节点之前插入值为 `val` 的链节点。 -- 尾部插入元素:在链表尾部插入值为 `val` 的链节点。 -- 中间插入元素:在链表第 `i` 个链节点之前插入值为 `val` 的链节点。 +- 链表头部插入元素:在链表第 `1` 个链节点之前插入值为 `val` 的链节点。 +- 链表尾部插入元素:在链表尾部插入值为 `val` 的链节点。 +- 链表中间插入元素:在链表第 `i` 个链节点之前插入值为 `val` 的链节点。 接下来我们分别讲解一下。 -#### 2.5.1 头部插入元素 +#### 2.5.1 链表头部插入元素 算法实现的步骤为: @@ -149,6 +149,8 @@ def find(self, val): - 然后将 `node` 的 `next` 指针指向链表的头节点 `head`。 - 再将链表的头节点 `head ` 指向 `node`。 +![](https://qcdn.itcharge.cn/images/20211208180101.png) + 因为在链表头部插入链节点与链表的长度无关,所以该算法的时间复杂度为 $O(1)$。 **「在链表头部插入值为 `val` 元素」** 的代码如下: @@ -170,6 +172,8 @@ def insertFront(self, val): - 通过链节点的 `next` 指针移动 `cur` 指针,从而遍历链表,直到 `cur.next == None`。 - 令 `cur.next` 指向将新的链节点 `node`。 +![](https://qcdn.itcharge.cn/images/20211208180111.png) + 因为将 `cur` 从链表头部移动到尾部的操作次数是 `n` 次,所以该算法的时间复杂度是 $O(n)$。 **「在链表尾部插入值为 `val` 的元素」** 的代码如下: @@ -191,9 +195,12 @@ def insertRear(self, val): - 使用指针变量 `cur` 和一个计数器 `count`。令 `cur` 指向链表的头节点,`count` 初始值赋值为 `0`。 - 沿着链节点的 `next` 指针遍历链表,指针变量 `cur` 每指向一个链节点,计数器就做一次计数。 - 当 `count == index - 1` 时,说明遍历到了第 `index - 1` 个链节点,此时停止遍历。 +- 创建一个值为 `val` 的链节点 `node`。 - 将 `node.next` 指向 `cur.next`。 - 然后令 `cur.next` 指向 `node`。 +![](https://qcdn.itcharge.cn/images/20211208180121.png) + 因为将 `cur` 从链表头部移动到第 `i` 个链节点之前的操作平均时间复杂度是 $O(n)$,所以该算法的时间复杂度是 $O(n)$。 **「在链表第 `i` 个链节点之前插入值为 `val` 的元素」** 的代码如下: @@ -247,42 +254,46 @@ def change(self, index, val): 链表的删除元素操作同样分为三种情况: -- 删除链表头部元素:删除链表的第 `1` 个链节点。 -- 删除链表尾部元素:删除链表末尾最后 `1` 个链节点。 -- 删除链表中间元素:删除链表第 `i` 个链节点。 +- 链表头部删除元素:删除链表的第 `1` 个链节点。 +- 链表尾部删除元素:删除链表末尾最后 `1` 个链节点。 +- 链表中间删除元素:删除链表第 `i` 个链节点。 接下来我们分别讲解一下。 -#### 2.7.1 删除链表头部元素 +#### 2.7.1 链表头部删除元素 -删除链表头部元素的方法很简单,具体步骤如下: +链表头部删除元素的方法很简单,具体步骤如下: - 直接将 `self.head` 沿着 `next` 指针向右移动一步即可。 -因为只涉及到一步移动操作,所以此算法的时间复杂度为 $O(1)$。 +![](https://qcdn.itcharge.cn/images/20211208180131.png) -**「删除链表头部元素」** 的代码如下所示: +因为只涉及到 `1` 步移动操作,所以此算法的时间复杂度为 $O(1)$。 + +**「链表头部删除元素」** 的代码如下所示: ```Python -# 移除链表头部元素 +# 链表头部删除元素 def removeFront(self): if self.head: self.head = self.head.next ``` -#### 2.7.2 删除链表尾部元素 +#### 2.7.2 链表尾部删除元素 -删除链表尾部元素的方法也比价简单,具体步骤如下: +链表尾部删除元素的方法也比价简单,具体步骤如下: - 先使用指针变量 `cur` 沿着 `next` 指针移动到倒数第 `2` 个链节点。 - 然后将此节点的 `next` 指针指向 `None` 即可。 +![](https://qcdn.itcharge.cn/images/20211208180138.png) + 因为移动到链表尾部的操作次数为`n` 次,所以该算法的时间复杂度为 $O(n)$。 -**「删除链表尾部元素」** 的代码如下所示: +**「链表尾部删除元素」** 的代码如下所示: ```Python -# 移除链表尾部元素 +# 链表尾部删除元素 def removeRear(self): if not self.head.next: return 'Error' @@ -293,17 +304,19 @@ def removeRear(self): cur.next = None ``` -#### 2.7.3 删除链表中间元素 +#### 2.7.3 链表中间删除元素 删除链表中第 `i` 个元素的算法具体步骤如下: - 先使用指针变量 `cur` 移动到第 `i - 1` 个位置的链节点。 - 然后将 `cur` 的 `next` 指针,指向要第 `i` 个元素的下一个节点即可。 +![](https://qcdn.itcharge.cn/images/20211208180144.png) + **「删除链表中第 `i` 个元素」** 的代码如下所示: ```Python -# 移除链表中间元素 +# 链表中间删除元素 def removeInside(self, index): count = 0 cur = self.head @@ -327,18 +340,12 @@ def removeInside(self, index): 链表是最基础、最简单的数据结构。**「链表」** 是实现线性表的链式存储结构的基础。它使用一组任意的存储单元(可以是连续的,也可以是不连续的),来存储一组具有相同类型的数据。 -链表最大的优点在可以灵活的添加和删除元素。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素进行的时间复杂度为 $O(n)$。 +链表最大的优点在于可以灵活的添加和删除元素。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素操作的时间复杂度为 $O(n)$。 ## 参考资料 - 【文章】[链表理论基础 - 代码随想录](https://programmercarl.com/链表理论基础.html#链表理论基础) - -- 【文章】[Python 与 Java 中容器对比:List - 知乎](https://zhuanlan.zhihu.com/p/120312437) - - 【文章】[什么是链表 - 漫画算法 - 小灰的算法之旅 - 力扣](https://leetcode-cn.com/leetbook/read/journey-of-algorithm/5ozchs/) - - 【文章】[链表 - 数据结构与算法之美 - 极客时间](https://time.geekbang.org/column/article/41013) - - 【书籍】数据结构教程 第 2 版 - 唐发根 著 - - 【书籍】数据结构与算法 Python 语言描述 - 裘宗燕 著