88
99以单链表为例,链表的存储方式如下图所示。
1010
11- ![ ] ( https://qcdn.itcharge.cn/images/20211205151319 .png )
11+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180037 .png )
1212
13- 如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的数据信息 ,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 ` next ` 」。
13+ 如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的值 ,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 ` next ` 」。
1414
1515在链表中,数据元素之间的逻辑关系是通过指针来间接反映的。逻辑上相邻的数据元素在物理地址上可能相邻,可也能不相邻。其在物理地址上的表现是随机的。
1616
3636
3737从循环链表的任何一个节点出发都能找到任何其他节点。
3838
39- ![ ] ( https://qcdn.itcharge.cn/images/20211208103712 .png )
39+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180048 .png )
4040
4141接下来我们以单链表为例,介绍一下链表的基本操作。
4242
@@ -73,7 +73,7 @@ class LinkedList:
7373- 每获取一个数据元素,就为该数据元素生成一个新节点,将新节点插入到链表的尾部。
7474- 插入完毕之后返回第 ` 1 ` 个链节点的地址。
7575
76- 建立一个线性链表的时间复杂度为 $O(n)$,n 为线性表长度。
76+ 建立一个线性链表的时间复杂度为 $O(n)$,` n ` 为线性表长度。
7777
7878** 「建立一个线性链表」** 的代码如下:
7979
@@ -133,22 +133,24 @@ def find(self, val):
133133
134134### 2.5 插入元素
135135
136- 插入元素操作分为三种 :
136+ 链表中插入元素操作分为三种 :
137137
138- - 头部插入元素 :在链表第 ` 1 ` 个链节点之前插入值为 ` val ` 的链节点。
139- - 尾部插入元素 :在链表尾部插入值为 ` val ` 的链节点。
140- - 中间插入元素 :在链表第 ` i ` 个链节点之前插入值为 ` val ` 的链节点。
138+ - 链表头部插入元素 :在链表第 ` 1 ` 个链节点之前插入值为 ` val ` 的链节点。
139+ - 链表尾部插入元素 :在链表尾部插入值为 ` val ` 的链节点。
140+ - 链表中间插入元素 :在链表第 ` i ` 个链节点之前插入值为 ` val ` 的链节点。
141141
142142接下来我们分别讲解一下。
143143
144- #### 2.5.1 头部插入元素
144+ #### 2.5.1 链表头部插入元素
145145
146146算法实现的步骤为:
147147
148148- 先创建一个值为 ` val ` 的链节点 ` node ` 。
149149- 然后将 ` node ` 的 ` next ` 指针指向链表的头节点 ` head ` 。
150150- 再将链表的头节点 ` head ` 指向 ` node ` 。
151151
152+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180101.png )
153+
152154因为在链表头部插入链节点与链表的长度无关,所以该算法的时间复杂度为 $O(1)$。
153155
154156** 「在链表头部插入值为 ` val ` 元素」** 的代码如下:
@@ -170,6 +172,8 @@ def insertFront(self, val):
170172- 通过链节点的 ` next ` 指针移动 ` cur ` 指针,从而遍历链表,直到 ` cur.next == None ` 。
171173- 令 ` cur.next ` 指向将新的链节点 ` node ` 。
172174
175+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180111.png )
176+
173177因为将 ` cur ` 从链表头部移动到尾部的操作次数是 ` n ` 次,所以该算法的时间复杂度是 $O(n)$。
174178
175179** 「在链表尾部插入值为 ` val ` 的元素」** 的代码如下:
@@ -191,9 +195,12 @@ def insertRear(self, val):
191195- 使用指针变量 ` cur ` 和一个计数器 ` count ` 。令 ` cur ` 指向链表的头节点,` count ` 初始值赋值为 ` 0 ` 。
192196- 沿着链节点的 ` next ` 指针遍历链表,指针变量 ` cur ` 每指向一个链节点,计数器就做一次计数。
193197- 当 ` count == index - 1 ` 时,说明遍历到了第 ` index - 1 ` 个链节点,此时停止遍历。
198+ - 创建一个值为 ` val ` 的链节点 ` node ` 。
194199- 将 ` node.next ` 指向 ` cur.next ` 。
195200- 然后令 ` cur.next ` 指向 ` node ` 。
196201
202+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180121.png )
203+
197204因为将 ` cur ` 从链表头部移动到第 ` i ` 个链节点之前的操作平均时间复杂度是 $O(n)$,所以该算法的时间复杂度是 $O(n)$。
198205
199206** 「在链表第 ` i ` 个链节点之前插入值为 ` val ` 的元素」** 的代码如下:
@@ -247,42 +254,46 @@ def change(self, index, val):
247254
248255链表的删除元素操作同样分为三种情况:
249256
250- - 删除链表头部元素 :删除链表的第 ` 1 ` 个链节点。
251- - 删除链表尾部元素 :删除链表末尾最后 ` 1 ` 个链节点。
252- - 删除链表中间元素 :删除链表第 ` i ` 个链节点。
257+ - 链表头部删除元素 :删除链表的第 ` 1 ` 个链节点。
258+ - 链表尾部删除元素 :删除链表末尾最后 ` 1 ` 个链节点。
259+ - 链表中间删除元素 :删除链表第 ` i ` 个链节点。
253260
254261接下来我们分别讲解一下。
255262
256- #### 2.7.1 删除链表头部元素
263+ #### 2.7.1 链表头部删除元素
257264
258- 删除链表头部元素的方法很简单 ,具体步骤如下:
265+ 链表头部删除元素的方法很简单 ,具体步骤如下:
259266
260267- 直接将 ` self.head ` 沿着 ` next ` 指针向右移动一步即可。
261268
262- 因为只涉及到一步移动操作,所以此算法的时间复杂度为 $O(1)$。
269+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180131.png )
263270
264- ** 「删除链表头部元素」** 的代码如下所示:
271+ 因为只涉及到 ` 1 ` 步移动操作,所以此算法的时间复杂度为 $O(1)$。
272+
273+ ** 「链表头部删除元素」** 的代码如下所示:
265274
266275``` Python
267- # 移除链表头部元素
276+ # 链表头部删除元素
268277def removeFront (self ):
269278 if self .head:
270279 self .head = self .head.next
271280```
272281
273- #### 2.7.2 删除链表尾部元素
282+ #### 2.7.2 链表尾部删除元素
274283
275- 删除链表尾部元素的方法也比价简单 ,具体步骤如下:
284+ 链表尾部删除元素的方法也比价简单 ,具体步骤如下:
276285
277286- 先使用指针变量 ` cur ` 沿着 ` next ` 指针移动到倒数第 ` 2 ` 个链节点。
278287- 然后将此节点的 ` next ` 指针指向 ` None ` 即可。
279288
289+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180138.png )
290+
280291因为移动到链表尾部的操作次数为` n ` 次,所以该算法的时间复杂度为 $O(n)$。
281292
282- ** 「删除链表尾部元素 」** 的代码如下所示:
293+ ** 「链表尾部删除元素 」** 的代码如下所示:
283294
284295``` Python
285- # 移除链表尾部元素
296+ # 链表尾部删除元素
286297def removeRear (self ):
287298 if not self .head.next:
288299 return ' Error'
@@ -293,17 +304,19 @@ def removeRear(self):
293304 cur.next = None
294305```
295306
296- #### 2.7.3 删除链表中间元素
307+ #### 2.7.3 链表中间删除元素
297308
298309删除链表中第 ` i ` 个元素的算法具体步骤如下:
299310
300311- 先使用指针变量 ` cur ` 移动到第 ` i - 1 ` 个位置的链节点。
301312- 然后将 ` cur ` 的 ` next ` 指针,指向要第 ` i ` 个元素的下一个节点即可。
302313
314+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180144.png )
315+
303316** 「删除链表中第 ` i ` 个元素」** 的代码如下所示:
304317
305318``` Python
306- # 移除链表中间元素
319+ # 链表中间删除元素
307320def removeInside (self , index ):
308321 count = 0
309322 cur = self .head
@@ -327,18 +340,12 @@ def removeInside(self, index):
327340
328341链表是最基础、最简单的数据结构。** 「链表」** 是实现线性表的链式存储结构的基础。它使用一组任意的存储单元(可以是连续的,也可以是不连续的),来存储一组具有相同类型的数据。
329342
330- 链表最大的优点在可以灵活的添加和删除元素 。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素进行的时间复杂度为 $O(n)$。
343+ 链表最大的优点在于可以灵活的添加和删除元素 。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素操作的时间复杂度为 $O(n)$。
331344
332345## 参考资料
333346
334347- 【文章】[ 链表理论基础 - 代码随想录] ( https://programmercarl.com/链表理论基础.html#链表理论基础 )
335-
336- - 【文章】[ Python 与 Java 中容器对比:List - 知乎] ( https://zhuanlan.zhihu.com/p/120312437 )
337-
338348- 【文章】[ 什么是链表 - 漫画算法 - 小灰的算法之旅 - 力扣] ( https://leetcode-cn.com/leetbook/read/journey-of-algorithm/5ozchs/ )
339-
340349- 【文章】[ 链表 - 数据结构与算法之美 - 极客时间] ( https://time.geekbang.org/column/article/41013 )
341-
342350- 【书籍】数据结构教程 第 2 版 - 唐发根 著
343-
344351- 【书籍】数据结构与算法 Python 语言描述 - 裘宗燕 著
0 commit comments