Python3中内置的堆模块为:heapq
使用时直接导入即可:
import heapq
可以打印出heapq内置的方法:
print(dir(heapq))
在具体介绍几个常用函数之前,要明确一下,heapq默认支持的堆类型为:小根堆。
如果,希望使用大根堆,可通过对元素反向比较大小实现。
所谓反向比较大小,对int来说,即原本使用heapq存x为小根堆,那么现在使用heapq存(-x)即为大根堆了。
对于非int这种类型的数据,可通过重写大小比较函数:__lt__,__ge__等。
具体方法此处不赘述,本文主要记录heap的函数使用方法。
1. heapq.heapify(l: list)
将列表l转换为heap,在原地转换,线性时间复杂度。
2. heapq.heappush(heap: list, item)
将item添加进heap中,并重新维护heap成为一个堆。
FAQ:如何创建一个heap?
两种方式,1. 对于一个已经有数据的list,使用heapify函数直接将其转换为一个heap;2. 对于一个没有数据的空list,不断的使用heappush,构建一个heap。
3. heapq.heappop(heap: list)
弹出heap中的最小值作为返回值,并重新维护heap成为一个堆。当heap为空时,调用此函数会引发IndexError。
注意:在Python的heap模块中没有提供类似top()这样的函数,无法通过函数获取怼的根,可直接使用heap[0]进行索引。
4. heapq.heappushpop(heap: list, item)
将item添加进heap中,弹出heap中的最小值(即根)作为返回值,并重新维护heap成为一个堆。即,该函数相当于先调用了heappush(),再调用了heappop()(注意,确是有此顺序关系,即如果新插入的item为最小值会被弹出)。根据官方文档,该函数会比先后调用heappush,heappop效率要高。
import random
import heapq
l = [2,3,4,5,6]
random.shuffle(l)
heapq.heapify(l)
print(heapq.heappushpop(l, 1)) # 1
print(heapq.heappushpop(l, 7)) # 2
print(l) # [3, 4, 6, 7, 5]
5. heapq.heapreplace(heap: list, item)
与heappushpop相似,但顺序相反,先弹出heap的最小值(即根)作为返回值,再将item添加进heap中,并重新维护heap成为一个堆。同样,该操作比先后调用heappop,heappush效率要高。
1. heapq.merge(*iterators, key=None, reverse=False)
将多个已排序的输入合成为一个已排序的输出(迭代器对象)。注意该函数不会检查输入的数据是否已排序,而是假定每个输入流都是从小到大排序正确的。
key:指定带有单个参数的函数对象,用于从每个输入元素中提取比较键,默认为None,即直接比较元素值。
reverse:是否逆序,默认由小到大。注意,当标记reverse=True时,输入数据应该也保持逆序,即假定输入是由大到小排序正确的。
l1 = [2,4,6,7]
l2 = [1,3,5,8]
# [1, 2, 3, 4, 5, 6, 7, 8]
print(list(heapq.merge(l1, l2)))
# 以下为错误用法示例
# [2, 4, 6, 7, 1, 3, 5, 8]
print(list(heapq.merge(l1, l2, reverse=True)))
l1 = [7,6,4,2]
l2 = [8,5,3,1]
# 以下为错误用法示例
# [7, 6, 4, 2, 8, 5, 3, 1]
print(list(heapq.merge(l1, l2)))
# [8, 7, 6, 5, 4, 3, 2, 1]
print(list(heapq.merge(l1, l2, reverse=True)))
2. heapq.nlargest(n: int, iterable, key=None)
从可迭代的iterable对象数据中返回前n个最大元素组成的列表。
key:指定带有单个参数的函数对象,用于从每个输入元素中提取比较键,默认为None,即直接比较元素值。
3. heapq.nsmallest(n: int, iterable, key=None)
从可迭代的iterable对象数据中返回前n个最小元素组成的列表。
key:指定带有单个参数的函数对象,用于从每个输入元素中提取比较键,默认为None,即直接比较元素值。
注意:函数2和函数3在n值较小时性能较好。对于较大的值,建议使用sorted()函数进行排序,当n为1时,建议使用min(),max()函数替代。如果需要对同一数据对象重复调用这两个函数,建议将数据对象转换为真正的堆。
基于heap的内置函数,构建一个堆,并以此弹出,即可完成堆排序。
def heapsort(iterable):
l = []
for v in iterable:
heapq.heappush(l, v)
return [heapq.heappop(l) for i in range(len(l))]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0]))