8
8
9
9
以单链表为例,链表的存储方式如下图所示。
10
10
11
- ![ ] ( https://qcdn.itcharge.cn/images/20211205151319 .png )
11
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180037 .png )
12
12
13
- 如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的数据信息 ,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 ` next ` 」。
13
+ 如上图所示,链表通过将一组任意的存储单元串联在一起。其中,每个数据元素占用若干存储单元的组合称为一个「链节点」。为了将所有的节点串起来,每个链节点不仅要存放一个数据元素的值 ,还要存放一个指出这个数据元素在逻辑关系上的直接后继元素所在链节点的地址,该地址被称为「后继指针 ` next ` 」。
14
14
15
15
在链表中,数据元素之间的逻辑关系是通过指针来间接反映的。逻辑上相邻的数据元素在物理地址上可能相邻,可也能不相邻。其在物理地址上的表现是随机的。
16
16
36
36
37
37
从循环链表的任何一个节点出发都能找到任何其他节点。
38
38
39
- ![ ] ( https://qcdn.itcharge.cn/images/20211208103712 .png )
39
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180048 .png )
40
40
41
41
接下来我们以单链表为例,介绍一下链表的基本操作。
42
42
@@ -73,7 +73,7 @@ class LinkedList:
73
73
- 每获取一个数据元素,就为该数据元素生成一个新节点,将新节点插入到链表的尾部。
74
74
- 插入完毕之后返回第 ` 1 ` 个链节点的地址。
75
75
76
- 建立一个线性链表的时间复杂度为 $O(n)$,n 为线性表长度。
76
+ 建立一个线性链表的时间复杂度为 $O(n)$,` n ` 为线性表长度。
77
77
78
78
** 「建立一个线性链表」** 的代码如下:
79
79
@@ -133,22 +133,24 @@ def find(self, val):
133
133
134
134
### 2.5 插入元素
135
135
136
- 插入元素操作分为三种 :
136
+ 链表中插入元素操作分为三种 :
137
137
138
- - 头部插入元素 :在链表第 ` 1 ` 个链节点之前插入值为 ` val ` 的链节点。
139
- - 尾部插入元素 :在链表尾部插入值为 ` val ` 的链节点。
140
- - 中间插入元素 :在链表第 ` i ` 个链节点之前插入值为 ` val ` 的链节点。
138
+ - 链表头部插入元素 :在链表第 ` 1 ` 个链节点之前插入值为 ` val ` 的链节点。
139
+ - 链表尾部插入元素 :在链表尾部插入值为 ` val ` 的链节点。
140
+ - 链表中间插入元素 :在链表第 ` i ` 个链节点之前插入值为 ` val ` 的链节点。
141
141
142
142
接下来我们分别讲解一下。
143
143
144
- #### 2.5.1 头部插入元素
144
+ #### 2.5.1 链表头部插入元素
145
145
146
146
算法实现的步骤为:
147
147
148
148
- 先创建一个值为 ` val ` 的链节点 ` node ` 。
149
149
- 然后将 ` node ` 的 ` next ` 指针指向链表的头节点 ` head ` 。
150
150
- 再将链表的头节点 ` head ` 指向 ` node ` 。
151
151
152
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180101.png )
153
+
152
154
因为在链表头部插入链节点与链表的长度无关,所以该算法的时间复杂度为 $O(1)$。
153
155
154
156
** 「在链表头部插入值为 ` val ` 元素」** 的代码如下:
@@ -170,6 +172,8 @@ def insertFront(self, val):
170
172
- 通过链节点的 ` next ` 指针移动 ` cur ` 指针,从而遍历链表,直到 ` cur.next == None ` 。
171
173
- 令 ` cur.next ` 指向将新的链节点 ` node ` 。
172
174
175
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180111.png )
176
+
173
177
因为将 ` cur ` 从链表头部移动到尾部的操作次数是 ` n ` 次,所以该算法的时间复杂度是 $O(n)$。
174
178
175
179
** 「在链表尾部插入值为 ` val ` 的元素」** 的代码如下:
@@ -191,9 +195,12 @@ def insertRear(self, val):
191
195
- 使用指针变量 ` cur ` 和一个计数器 ` count ` 。令 ` cur ` 指向链表的头节点,` count ` 初始值赋值为 ` 0 ` 。
192
196
- 沿着链节点的 ` next ` 指针遍历链表,指针变量 ` cur ` 每指向一个链节点,计数器就做一次计数。
193
197
- 当 ` count == index - 1 ` 时,说明遍历到了第 ` index - 1 ` 个链节点,此时停止遍历。
198
+ - 创建一个值为 ` val ` 的链节点 ` node ` 。
194
199
- 将 ` node.next ` 指向 ` cur.next ` 。
195
200
- 然后令 ` cur.next ` 指向 ` node ` 。
196
201
202
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180121.png )
203
+
197
204
因为将 ` cur ` 从链表头部移动到第 ` i ` 个链节点之前的操作平均时间复杂度是 $O(n)$,所以该算法的时间复杂度是 $O(n)$。
198
205
199
206
** 「在链表第 ` i ` 个链节点之前插入值为 ` val ` 的元素」** 的代码如下:
@@ -247,42 +254,46 @@ def change(self, index, val):
247
254
248
255
链表的删除元素操作同样分为三种情况:
249
256
250
- - 删除链表头部元素 :删除链表的第 ` 1 ` 个链节点。
251
- - 删除链表尾部元素 :删除链表末尾最后 ` 1 ` 个链节点。
252
- - 删除链表中间元素 :删除链表第 ` i ` 个链节点。
257
+ - 链表头部删除元素 :删除链表的第 ` 1 ` 个链节点。
258
+ - 链表尾部删除元素 :删除链表末尾最后 ` 1 ` 个链节点。
259
+ - 链表中间删除元素 :删除链表第 ` i ` 个链节点。
253
260
254
261
接下来我们分别讲解一下。
255
262
256
- #### 2.7.1 删除链表头部元素
263
+ #### 2.7.1 链表头部删除元素
257
264
258
- 删除链表头部元素的方法很简单 ,具体步骤如下:
265
+ 链表头部删除元素的方法很简单 ,具体步骤如下:
259
266
260
267
- 直接将 ` self.head ` 沿着 ` next ` 指针向右移动一步即可。
261
268
262
- 因为只涉及到一步移动操作,所以此算法的时间复杂度为 $O(1)$。
269
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180131.png )
263
270
264
- ** 「删除链表头部元素」** 的代码如下所示:
271
+ 因为只涉及到 ` 1 ` 步移动操作,所以此算法的时间复杂度为 $O(1)$。
272
+
273
+ ** 「链表头部删除元素」** 的代码如下所示:
265
274
266
275
``` Python
267
- # 移除链表头部元素
276
+ # 链表头部删除元素
268
277
def removeFront (self ):
269
278
if self .head:
270
279
self .head = self .head.next
271
280
```
272
281
273
- #### 2.7.2 删除链表尾部元素
282
+ #### 2.7.2 链表尾部删除元素
274
283
275
- 删除链表尾部元素的方法也比价简单 ,具体步骤如下:
284
+ 链表尾部删除元素的方法也比价简单 ,具体步骤如下:
276
285
277
286
- 先使用指针变量 ` cur ` 沿着 ` next ` 指针移动到倒数第 ` 2 ` 个链节点。
278
287
- 然后将此节点的 ` next ` 指针指向 ` None ` 即可。
279
288
289
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180138.png )
290
+
280
291
因为移动到链表尾部的操作次数为` n ` 次,所以该算法的时间复杂度为 $O(n)$。
281
292
282
- ** 「删除链表尾部元素 」** 的代码如下所示:
293
+ ** 「链表尾部删除元素 」** 的代码如下所示:
283
294
284
295
``` Python
285
- # 移除链表尾部元素
296
+ # 链表尾部删除元素
286
297
def removeRear (self ):
287
298
if not self .head.next:
288
299
return ' Error'
@@ -293,17 +304,19 @@ def removeRear(self):
293
304
cur.next = None
294
305
```
295
306
296
- #### 2.7.3 删除链表中间元素
307
+ #### 2.7.3 链表中间删除元素
297
308
298
309
删除链表中第 ` i ` 个元素的算法具体步骤如下:
299
310
300
311
- 先使用指针变量 ` cur ` 移动到第 ` i - 1 ` 个位置的链节点。
301
312
- 然后将 ` cur ` 的 ` next ` 指针,指向要第 ` i ` 个元素的下一个节点即可。
302
313
314
+ ![ ] ( https://qcdn.itcharge.cn/images/20211208180144.png )
315
+
303
316
** 「删除链表中第 ` i ` 个元素」** 的代码如下所示:
304
317
305
318
``` Python
306
- # 移除链表中间元素
319
+ # 链表中间删除元素
307
320
def removeInside (self , index ):
308
321
count = 0
309
322
cur = self .head
@@ -327,18 +340,12 @@ def removeInside(self, index):
327
340
328
341
链表是最基础、最简单的数据结构。** 「链表」** 是实现线性表的链式存储结构的基础。它使用一组任意的存储单元(可以是连续的,也可以是不连续的),来存储一组具有相同类型的数据。
329
342
330
- 链表最大的优点在可以灵活的添加和删除元素 。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素进行的时间复杂度为 $O(n)$。
343
+ 链表最大的优点在于可以灵活的添加和删除元素 。链表进行访问元素、改变元素操作的时间复杂度为 $O(n)$,进行头部插入、尾部插入、头部删除、尾部删除元素操作的时间复杂度是 $O(1)$,普通情况下进行插入、删除元素操作的时间复杂度为 $O(n)$。
331
344
332
345
## 参考资料
333
346
334
347
- 【文章】[ 链表理论基础 - 代码随想录] ( https://programmercarl.com/链表理论基础.html#链表理论基础 )
335
-
336
- - 【文章】[ Python 与 Java 中容器对比:List - 知乎] ( https://zhuanlan.zhihu.com/p/120312437 )
337
-
338
348
- 【文章】[ 什么是链表 - 漫画算法 - 小灰的算法之旅 - 力扣] ( https://leetcode-cn.com/leetbook/read/journey-of-algorithm/5ozchs/ )
339
-
340
349
- 【文章】[ 链表 - 数据结构与算法之美 - 极客时间] ( https://time.geekbang.org/column/article/41013 )
341
-
342
350
- 【书籍】数据结构教程 第 2 版 - 唐发根 著
343
-
344
351
- 【书籍】数据结构与算法 Python 语言描述 - 裘宗燕 著
0 commit comments