python模块之heapq模块

1,610 阅读3分钟

1.heqpq介绍

堆是非线性的树形的数据结构,有2种堆,最大堆与最小堆。python的heapq模块默认的是最小堆。堆数据结构最重要的特征是heap[0] 永远是最小的元素。

最大堆:树中父节点的值总是大于等于任意子节点的值

最小堆:树中父节点的值总是大于等于任意子节点的值

我们一般使用二叉堆来实现优先级队列,它的内部调整算法复杂度为logN

2.方法介绍

2.1 heappush方法

heappush(heap, item):将item压入堆heqp中。

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq.heappush(list1, 12)
print(list1)

result:

[1, 3, 5, 2, 6, 8, 9, 3, 12]

2.2 heappop方法

heappop(heap):从堆item弹出最小值。

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq1 = heapq.heappop(list1)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9]
print(heapq1)

result:

1

注:如果不是压入堆中,而是通过heapq追加一个数值,堆的函数是不能操作该元素的,或者说该元素对堆而言是不可感知的。下面来看一个具体的例子:

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
list1.append(-1)
heapq2 = heapq.heappop(list1)
print(heapq2)

result:

1

前后对比可以发现,-1并没有被堆感知到,否则弹出的最小元素应该是-1而不是1

2.3 heapify方法

heapq.heapify(list):参数必须是list,此函数必须将list变成堆,实时操作。

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq1 = heapq.heapify(list1)
print(list1)

result:

[1, 2, 5, 3, 6, 8, 9, 3]

处理后list1已经成为了堆(最小的元素1排在第一位)

2.4 heappushpop方法

heappushpop(heap, item): heappush方法和heappop方法的合体,先heappush(heap, item),再heappop(heap)

2.4.1 heappush+ heappop的效果

先heappush

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq.heappush(list1, 12)
print(list1)

result:

[1, 3, 5, 2, 6, 8, 9, 3, 12]

再heappop

heapq1 = heapq.heappop(list1)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9, 12]

2.4.2 heappushpop的效果

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq.heappushpop(list1, 12)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9, 12]

2.5 heapreplace方法

heapreplace(heap, item): heappop方法和heappush方法的合体,先heappop(heap),再heappush(heap, item)

注意该方法与heappushpop方法的差异

2.5.1 heappop+ heappush的效果

先heappop

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq1 = heapq.heappop(list1)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9]

再heappush

heapq.heappush(list1, 12)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9, 12]

2.5.2 heapreplace的效果

import heapq
​
list1 = [1, 3, 5, 2, 6, 8, 9, 3]
heapq.heapreplace(list1, 12)
print(list1)

result:

[3, 2, 5, 3, 6, 8, 9, 12]

2.6 merge方法

merge(*iterables): 将多个堆进行合并

import heapq
​
list1 = [1, 3, 5, 7]
list2 = [2, 4, 6, 8]
new_heapq = heapq.merge(list1, list2)
print(new_heapq)

result:

<generator object merge at 0x0000024280537748>

可以看出,该方法会返回一个生成器,可以使用迭代或者list()方法获取其内容

print(list(new_heapq))

result:

[1, 2, 3, 4, 5, 6, 7, 8]

2.7 nlargest方法

heapq.nlargest(n, iterable):获取iterable中最大的n个值

import heapq
​
list1 = [1, 3, 5, 7, 2, 4, 6, 8]
print(heapq.nlargest(2, list1))

result:

[8, 7]

这里是获取了list1中最大的2个数

2.8 nsmallest方法

heapq.nsmallest(n, iterable):获取iterable中最大的n个值

import heapq
​
list1 = [1, 3, 5, 7, 2, 4, 6, 8]
print(heapq.nsmallest(2, list1))

result:

[1, 2]

这里是获取了list1中最小的2个数 对于nlargest方法和nsmallest方法,当要查找的元素个数相对比较小的时候,函数nlargest() 和nsmallest() 是很合适的。如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用min() 和max() 函数会更快些。类似的,如果N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点(sorted(items)[:N] 或者是sorted(items)[-N:])。需要在正确场合使用函数nlargest() 和nsmallest() 才能发挥它们的优势(如果N 快接近集合大小了,那么使用排序操作会更好些)。