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 快接近集合大小了,那么使用排序操作会更好些)。