官网地址:
heapq — 堆队列算法
堆本身还是一个树结构,通常还是使用数组进行存储,方便操作。
我们找到py有一个基本语法是数组下标从零开始,py中的堆也是这样实现的,问题就是使得父子关系不那么直观。
C++中的堆是大顶堆(大根堆),一般也是常用的一种堆,但是py中还是选择了实现一个小顶堆。
这还不算完,heap库还提供了一些和堆排序相关的通用函数。
在官方文档的介绍中,最后的两个函数(nlargest和nsmallest函数)在n比较小的情况下合适,太大了建议使用sorted,如果是n=1,直接max/min不香吗。
import heapq
from icecream import ic
def heapsort(iterable):
'''将列表中的每一个元素压入堆(其实就是个列表),最后弹出'''
h = []
for value in iterable:
heapq.heappush(h,value)
return [heapq.heappop(h) for _ in range(len(h))]
print(heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0]))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
def heapsort2(iterable):
'''这个案例是突出本地排序,而不是像counter那样存储到一个类的实例中'''
heapq.heapify(iterable)
return iterable
print(heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0]))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 其他方法的介绍,这部分有一点就是他内部是一个树结构,感兴趣的自己草纸上画一下,看看有没有问题
h = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
heapq.heapify(h)
ic(h)
heapq.heappush(h, 10)
ic(h)
ic(heapq.heappop(h))
ic(h)
heapq.heappushpop(h, 15)
ic(h)
heapq.heapreplace(h, 16)
ic(h)
# 这不看一下push一个更小值两个函数的区别
ic(heapq.heappushpop(h, -1))
ic(heapq.heapreplace(h, -2))
ic(h)
'''这部分的结果:
ic| h: [0, 1, 2, 6, 3, 5, 4, 7, 8, 9]
ic| h: [0, 1, 2, 6, 3, 5, 4, 7, 8, 9, 10]
ic| heapq.heappop(h): 0
ic| h: [1, 3, 2, 6, 9, 5, 4, 7, 8, 10]
ic| h: [2, 3, 4, 6, 9, 5, 15, 7, 8, 10]
ic| h: [3, 6, 4, 7, 9, 5, 15, 16, 8, 10]
ic| heapq.heappushpop(h, -1): -1
ic| heapq.heapreplace(h, -2): 3
ic| h: [-2, 6, 4, 7, 9, 5, 15, 16, 8, 10]'''
# 通用函数的介绍
a = [1,3,5]
b = [0,4,8]
c = [11,13,15]
x = heapq.merge(a,b,c)
for i in x:
print(i,end=' ')
# 0 1 3 4 5 8 11 13 15
ic(h)
largest = heapq.nlargest(2, h)
ic(largest)
smallest = heapq.nsmallest(2,h)
ic(smallest)
ic(h)
'''这部分的结果
ic| h: [-2, 6, 4, 7, 9, 5, 15, 16, 8, 10]
ic| largest: [16, 15]
ic| smallest: [-2, 4]
ic| h: [-2, 6, 4, 7, 9, 5, 15, 16, 8, 10]
对h有影响'''