4
4
5
5
##heapq
6
6
7
- 堆(heap),是一种数据结构。用维基百科中的说明 :
7
+ 堆(heap),是一种数据结构,引用维基百科中的说明 :
8
8
9
9
> 堆(英语:heap),是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。
10
10
11
- 对于这个新的概念,读者不要感觉心慌意乱或者恐惧 ,因为它本质上不是新东西,而是在我们已经熟知的知识基础上的扩展 。
11
+ 对于这个新的概念,读者不要心慌意乱或者恐惧 ,因为它本质上不是新东西,而是在我们已经熟知的知识基础上的扩展出来的内容 。
12
12
13
13
堆的实现是通过构造二叉堆,也就是一种二叉树。
14
14
15
15
###基本知识
16
16
17
- 这是一颗在苏州很常见的香樟树 ,马路两边、公园里随处可见。
17
+ 这是一棵在苏州很常见的香樟树 ,马路两边、公园里随处可见,特别是在艳阳高照的时候,它的树荫能把路面遮盖 。
18
18
19
19
![ ] ( ./2images/22301.jpg )
20
20
21
- 但是,在编程中,我们常说的树通常不是上图那样的,而是这样的 :
21
+ 但是,在编程中,我们常说的树是这样的 :
22
22
23
23
![ ] ( ./2images/22302.jpg )
24
24
25
- 跟真实现实生活中看到的树反过来,也就是 “根”在上面 。为什么这样呢?我想主要是画着更方便吧。但是,我觉这棵树,是完全写实的作品。我本人做为一名隐姓埋名多年的抽象派画家 ,不喜欢这样的树,我画出来的是这样的:
25
+ 这是一棵 “根”在上面树,也是编程中常说的树 。为什么这样呢?我想主要是画着更方便吧。上面那棵树虽然根在上面了,还完全是写实的作品,本人做为一名隐姓埋名多年的抽象派画家 ,不喜欢这样的树,我画出来的是这样的:
26
26
27
27
![ ] ( ./2images/22303.jpg )
28
28
29
29
这棵树有两根枝杈,可不要小看这两根枝杈哦,《道德经》上不是说“一生二,二生三,三生万物”。一就是下面那个干,二就是两个枝杈,每个枝杈还可以看做下一个一,然后再有两个枝杈,如此不断重复(这简直就是递归呀),就成为了一棵大树。
30
30
31
- 我的确很佩服我自己的后现代抽象派的作品。但是,我更喜欢把这棵树画成这样:
31
+ 这棵树画成这样就更符合编程的习惯了,可以向下不断延伸。
32
32
33
33
![ ] ( ./2images/22304.jpg )
34
34
35
- 并且给它一个正规的名字:二叉树
35
+ 并且给它一个正规的名字:二叉树。
36
36
37
37
![ ] ( ./2images/22305.jpg )
38
38
39
39
这个也是二叉树,完全脱胎于我所画的后现代抽象主义作品。但是略有不同,这幅图在各个枝杈上显示的是数字。这种类型的“树”就编程语言中所说的二叉树,维基百科曰:
40
40
41
41
> 在计算机科学中,二叉樹(英语:Binary tree)是每個節點最多有兩個子樹的樹結構。通常子樹被稱作「左子樹」(left subtree)和「右子樹」(right subtree)。二叉樹常被用於實現二叉查找樹和二叉堆。
42
42
43
- 在上图的二叉树中,最顶端的那个数字就相当于树根,也就称作“根”。每个数字所在位置成为一个节点,每个节点向下分散出两个“子节点”。就上图的二叉树,在最后一层,并不是所有节点都有两个子节点,这类二叉树又称为完全二叉树(Complete Binary Tree),也有的二叉树,所有的节点都有两个子节点,这类二叉树称作满二叉树(Full Binarry Tree),如下图:
43
+ 在上图的二叉树中,最顶端的那个数字就相当于树根,也就称作“根”。每个数字所在位置成为一个节点,每个节点向下分散出两个“子节点”。并不是所有节点都有两个子节点。这类二叉树又称为完全二叉树(Complete Binary Tree)。
44
+
45
+ 也有的二叉树,所有的节点都有两个子节点,这类二叉树称作满二叉树(Full Binarry Tree),如下图:
44
46
45
47
![ ] ( ./2images/22306.jpg )
46
48
47
- 下面讨论的对象是实现二叉堆就是通过二叉树实现的。其应该具有如下特点 :
49
+ 下面讨论的对象是通过二叉树实现的,其具有如下特点 :
48
50
49
51
- 节点的值大于等于(或者小于等于)任何子节点的值。
50
52
- 节点左子树和右子树是一个二叉堆。如果父节点的值总大于等于任何一个子节点的值,其为最大堆;若父节点值总小于等于子节点值,为最小堆。上面图示中的完全二叉树,就表示一个最小堆。
51
53
52
54
堆的类型还有别的,如斐波那契堆等,但很少用。所以,通常就将二叉堆也说成堆。下面所说的堆,就是二叉堆。而二叉堆又是用二叉树实现的。
53
55
54
- ###堆的存储
55
-
56
56
堆用列表(有的语言中成为数组)来表示。如下图所示:
57
57
58
58
![ ] ( ./2images/22307.jpg )
63
63
64
64
如果将上面的逻辑结构转换为存储结构,读者就能看出来了,不再是按照顺序排列的了。
65
65
66
- 关于堆的各种,如插入、删除、排序等,本节不会专门讲授编码方法,读者可以参与有关资料。但是,下面要介绍如何用python中的模块heapq来实现这些操作 。
66
+ 关于堆的各种,如插入、删除、排序等,本节不会专门讲授编码方法,读者可以参与有关资料。但是,下面要介绍如何用Python中的模块 ` heapq ` 来实现这些操作 。
67
67
68
68
###heapq模块
69
69
70
- heapq中的heap是堆 ,q就是queue(队列)的缩写。此模块包括:
70
+ ` heapq ` 中的heap是堆 ,q就是queue(队列)的缩写。此模块包括:
71
71
72
72
>>> import heapq
73
73
>>> heapq.__all__
74
74
['heappush', 'heappop', 'heapify', 'heapreplace', 'merge', 'nlargest', 'nsmallest', 'heappushpop']
75
75
76
76
依次查看这些函数的使用方法。
77
77
78
- ** heappush(heap, x)** :将x压入对heap(这是一个列表)
78
+ ** heappush(heap, x)** :将x压入堆heap
79
79
80
80
Help on built-in function heappush in module _heapq:
81
81
@@ -94,7 +94,7 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
94
94
>>> heap
95
95
[0, 2, 3, 9, 4, 8]
96
96
97
- 请读者注意我上面的操作,在向堆增加数值的时候,我并没有严格按照什么顺序, 是随意的。但是,当我查看堆的数据时,显示给我的是一个有一定顺序的数据结构 。这种顺序不是按照从小到大,而是按照前面所说的完全二叉树的方式排列。 显示的是存储结构,可以把它还原为逻辑结构,看看是不是一颗二叉树 。
97
+ 请读者注意上面的操作,在向堆增加数值的时候并没有严格按照什么顺序, 是随意的。但是,当查看堆的数据时,显示的是一个有一定顺序的数据结构 。这种顺序不是按照从小到大,而是按照前面所说的完全二叉树的方式排列, 显示的是存储结构,可以把它还原为逻辑结构,看看是不是一棵二叉树 。
98
98
99
99
![ ] ( ./2images/22309.jpg )
100
100
@@ -120,7 +120,7 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
120
120
>>> hl
121
121
[0, 3, 1, 4, 9, 6, 2, 5, 8]
122
122
123
- 经过这样的操作,列表hl就变成了堆(注意观察堆的顺序,和列表不同),可以对hl (堆)使用heappop()或者heappush() 等函数了。否则,不可。
123
+ 经过这样的操作,列表 ` hl ` 就变成了堆(堆的顺序和列表不同),可以对 ` hl ` (堆)使用 ` heappop() ` 或者 ` heappush() ` 等函数了。否则,不可。
124
124
125
125
>>> heapq.heappop(hl)
126
126
0
@@ -132,7 +132,7 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
132
132
>>> hl
133
133
[2, 3, 5, 4, 9, 6, 8, 9]
134
134
135
- 不要认为堆里面只能放数字,之所以用数字 ,是因为对它的逻辑结构比较好理解。
135
+ 不要认为堆里面只能放数字,举例中之所以用数字 ,是因为对它的逻辑结构比较好理解。
136
136
137
137
>>> heapq.heappush(hl, "q")
138
138
>>> hl
@@ -143,7 +143,7 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
143
143
144
144
** heapreplace()**
145
145
146
- 是heappop()和heappush() 的联合,也就是删除一个,同时加入一个。例如:
146
+ 是 ` heappop() ` 和 ` heappush() ` 的联合,也就是删除一个,同时加入一个。例如:
147
147
148
148
>>> heap
149
149
[2, 4, 3, 9, 8]
@@ -152,19 +152,17 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
152
152
>>> heap
153
153
[3, 4, 3.14, 9, 8]
154
154
155
- 先简单罗列关于对的几个常用函数。那么堆在编程实践中的用途在哪方面呢?主要在排序上。一提到排序,读者肯定想到的是sorted()或者列表中的sort(),不错,这两个都是常用的函数,而且在一般情况下已经足够使用了。如果再使用堆排序,相对上述方法应该有优势。
156
-
157
- 堆排序的优势不仅更快,更重要的是有效地使用内存,当然,另外一个也不同忽视,就是简单易用。比如前面操作的,删除数列中最小的值,就是在排序基础上进行的操作。
155
+ 先简单罗列关于堆的几个常用函数。那么堆在编程实践中的用途有哪些呢?排序是一个应用方面。一提到排序,读者肯定想到的是` sorted() ` 或者列表中的` sort() ` ,这两个都是常用的函数,而且在一般情况下已经足够使用了。但如果使用堆排序,相对于其他排序,也有自己的优势。不同的排序方法有不同的特点,读者可以自行深入研究不同排序的优劣。
158
156
159
- ##deque模块
157
+ ##deque
160
158
161
- 有这样一个问题:一个列表,比如是` [1,2, 3] ` ,我打算在最右边增加一个数字 。
159
+ 有这样一个问题:一个列表,比如是` [1, 2, 3] ` ,在最右边增加一个数字 。
162
160
163
- 这也太简单了,不就是用` append() ` 这个内建函数, 追加一个吗?
161
+ 这也太简单了,不就是用` append() ` 追加一个吗?
164
162
165
- 这是简单,我要得寸进尺 ,能不能在最左边增加一个数字呢?
163
+ 这是简单。但,得寸进尺 ,能不能在最左边增加一个数字呢?
166
164
167
- 这个嘛,应该有办法。 不过得想想了。读者在向下阅读的时候 ,能不能想出一个方法来?
165
+ 这个应该有办法, 不过得想想了。读者在向下阅读之前候 ,能不能想出一个方法来?
168
166
169
167
>>> lst = [1, 2, 3]
170
168
>>> lst.append(4)
@@ -175,20 +173,19 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
175
173
>>> nl
176
174
[7, 1, 2, 3, 4]
177
175
178
- 你或许还有别的方法。但是,python为我们提供了一个更简单的模块 ,来解决这个问题。
176
+ 你或许还有别的方法。但是,Python为我们提供了一个更简单的模块 ,来解决这个问题。
179
177
180
178
>>> from collections import deque
181
179
182
- 这次用这种引用方法,因为collections模块中东西很多,我们只用到deque 。
180
+ 这次用这种引用方法是因为 ` collections ` 模块中东西很多,我们只用到 ` deque ` 。
183
181
184
- >>> lst
185
- [1, 2, 3, 4]
182
+ >>> lst = [1, 2, 3, 4]
186
183
187
- 还是这个列表。试试分别从右边和左边增加数
184
+ 还是这个列表,试试分别从右边和左边增加数字。
188
185
189
186
>>> qlst = deque(lst)
190
187
191
- 这是必须的 ,将列表转化为deque。deque在汉语中有一个名字,叫做“双端队列”(double-ended queue)。
188
+ 这是必需的 ,将列表转化为deque。deque在汉语中有一个名字,叫做“双端队列”(double-ended queue)。
192
189
193
190
>>> qlst.append(5) #从右边增加
194
191
>>> qlst
@@ -208,31 +205,31 @@ heapq中的heap是堆,q就是queue(队列)的缩写。此模块包括:
208
205
>>> qlst
209
206
deque([ 1, 2, 3, 4] )
210
207
211
- 删除也分左右。下面这个,请读者仔细观察,更有点意思 。
208
+ 删除也分左右。下面这个,请读者仔细观察。
212
209
213
210
>>> qlst.rotate(3)
214
211
>>> qlst
215
212
deque([ 2, 3, 4, 1] )
216
213
217
- rotate()的功能是将[ 1, 2, 3, 4] 的首位连起来 ,你就想象一个圆环,在上面有1,2,3, 4几个数字。如果一开始正对着你的是1,依顺时针方向排列,就是从1开始的数列,如下图所示:
214
+ rotate()的功能是将[ 1, 2, 3, 4] 的首尾连起来 ,你就想象一个圆环,在上面有1, 2, 3, 4几个数字。如果一开始正对着你的是1,依顺时针方向排列,就是从1开始的数列,如下图所示:
218
215
219
216
![ ] ( ./2images/22310.jpg )
220
217
221
218
经过` rotate() ` ,这个环就发生旋转了,如果是` rotate(3) ` ,表示每个数字按照顺时针方向前进三个位置,于是变成了:
222
219
223
220
![ ] ( ./2images/22311.jpg )
224
221
225
- 请原谅我的后现代注意超级抽象派作图方式。从图中可以看出,数列变成了[ 2, 3, 4, 1] 。 rotate()作用就好像在拨转这个圆环。
222
+ 请原谅我的后现代注意超级抽象派作图方式。从图中可以看出,数列变成了` [2, 3, 4, 1] ` 。 ` rotate() ` 作用就好像在拨转这个圆环。
226
223
227
224
>>> qlst
228
225
deque([ 3, 4, 1, 2] )
229
226
>>> qlst.rotate(-1)
230
227
>>> qlst
231
228
deque([ 4, 1, 2, 3] )
232
229
233
- 如果参数是复数 ,那么就逆时针转。
230
+ 如果参数是负数 ,那么就逆时针转。
234
231
235
- 在deque中,还有extend和extendleft方法 。读者可自己调试。
232
+ 在deque中,还有 ` extend() ` 和 ` extendleft() ` 方法 。读者可自己调试。
236
233
237
234
------
238
235
0 commit comments