【数据结构与算法】用 Python 实现堆
堆 (heap)
又被为优先队列 (priority queue)。尽管名为优先队列,但堆并不是队列。回忆一下,在队列中,我们可以进行的限定操作是 dequeue 和 enqueue。
dequeue 是按照进入队列的先后顺序来取出元素。而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素。
性质
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。
- 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
- 堆总是一棵完全二叉树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
python 内置方法 heapq 创建堆
heaqp 模块提供了堆队列算法的实现,也称为优先级队列算法。
要创建堆,请使用初始化为 [] 的列表,或者可以通过函数 heapify()将填充列表转换为堆。
提供以下功能:
heapq.heappush(堆,项目)
将值项推入堆中,保持堆不变。
heapq.heapify(x)
在线性时间内将列表 x 转换为堆。
heapq.heappop(堆)
弹出并返回堆中的最小项,保持堆不变。如果堆是空的,则引发 IndexError。
import heapq
# 1 heappush生成堆+ heappop把堆从小到大pop出来
heap = []
data = [1,3,5,7,9,2,4,6,8,0]
for i in data:
heapq.heappush(heap,i)
print(heap)
lis = []
while heap:
lis.append(heapq.heappop(heap))
print(lis)
#2 heapify生成堆+ heappop把堆从小到大pop出来
data2 = [1,5,3,2,9,5]
heapq.heapify(data2)
print(data2)
lis2 = []
while data2:
lis2.append(heapq.heappop(data2))
print(lis2)
#输出结果
[0, 1, 2, 6, 3, 5, 4, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 9, 5]
[1, 2, 3, 5, 5, 9]
heapq 实现的是最小堆,下面我们自己实现一个最大堆
- 堆的主要操作是插入元素和删除最大元素
- 在插入或者删除操作之后,我们必须保持该堆本来的性质: 1. 完全二叉树 2. 每个节点值都大于或等于它的子节点
上浮(Promotion)
情境: 子节点的值比父节点的值大,比如在末尾添加一个较大的子节点
消除这种违反项:
- 交换子节点和父节点的值
- 重复这个过程直到堆的顺序恢复正常
def _upheap(heap, node):
item = heap[node]
while node > 0:
parent_node = (node - 1) >> 1
parent = heap[parent_node]
if item > parent:
heap[node] = parent
node = parent_node
continue
break
heap[node] = item
下沉(Demotion)
情境: 父节点的值比子节点的值小,比如删除根节点后拿较小的节点替换
消除这种违反项:
- 交换父节点和比它大的子节点的值
- 重复这个过程直到堆的顺序恢复正常
def _downheap(heap, node):
item = heap[node]
left_child_node = 2 * node + 1
study