堆是一种特殊的树结构, 能够快速定位最大值或最小值, 是实现堆排序, 优先队列的关键,同时优先队列主要应用在 事件处理 和 任务调度 等场景。
在Python中,堆分为大根堆和小根堆,它们本质上都是一棵完全二叉树,只是它们的节点大小关系不同:
大根堆和小根堆在实现上是类似的,唯一的区别就是插入的时候需要加上符号(大根堆为负,小根堆为正),取出元素时再次加上符号即可。使用 heapq 模块,只需要将插入堆中的元素加上负号就可以将大根堆变成小根堆,然后通过 heappop 函数弹出堆顶元素(也就是最小的元素),即可实现弹出堆内的最大元素。
import heapq
# 小根堆
min_heap = []
heapq.heappush(min_heap, 1)
heapq.heappush(min_heap, 2)
heapq.heappush(min_heap, 3)
# 输出结果为 [1, 2, 3]
print(min_heap)
# 大根堆
max_heap = []
for num in [1, 2, 3]:
heapq.heappush(max_heap, -num) # 注意负号!!!
# 输出结果为 [-3, -2, -1]
print(max_heap)
# 从大根堆中取出最大的元素
print(-heapq.heappop(max_heap)) # 输出 3 # 注意负号!!!
在 Python 中,我们可以使用内置的 heapq 模块来实现堆操作,它默认实现的是小根堆。如果需要实现大根堆,只需要将插入堆中的元素取相反数即可。
Python的heapq模块提供了一些堆操作的函数。其中最常用的是:
堆的应用:堆的应用非常广泛,比如在优先队列、排序、图算法中均有应用。在Python中,我们可以使用heapq模块中的函数来解决这些问题。下面是一些例子:
(1)使用堆排序
import heapq
nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
# 将列表转换成小根堆
heapq.heapify(nums)
# 按照从小到大的顺序弹出堆中的元素
sorted_nums = []
while nums:
sorted_nums.append(heapq.heappop(nums))
print(sorted_nums)
(2)使用堆实现优先队列
这是一个简单的优先队列的实现,其中每个元素都有一个对应的优先级。我们可以使用push函数将元素添加到队列中,使用pop函数弹出优先级最高的元素。注意,这里使用了一个_index变量来确保在优先级相等的情况下,先加入队列的元素先被弹出。
import heapq
class PriorityQueue:
# 始化了一个空的列表 heap 和一个变量 index,作为优先队列的底层数据结构和索引值。
def __init__(self):
self._heap = []
self._index = 0
# 在 push 方法中,将元素 item 和优先级 priority 加入到 heap 中,并为了保持小根堆的性质,将优先级 priority 按照相反数加入到堆中(即插入 -priority)。同时,为了确保后续插入的元素按照插入的顺序排序,将 index 作为第二个元素加入到堆中。最后,将插入的元素以元组的形式加入到堆中。
def push(self, item, priority):
heapq.heappush(self._heap, (-priority, self._index, item))
self._index += 1
# 在 pop 方法中,弹出堆顶元素(也就是优先级最高的元素),并返回元组中的最后一个元素(也就是 item)。
def pop(self):
return heapq.heappop(self._heap)[-1]
(3)使用堆实现最小生成树
import heapq
def prim(graph):
visited = set()
edges = []
start_vertex = next(iter(graph))
visited.add(start_vertex)
for neighbor, weight in graph[start_vertex].items():
heapq.heappush(edges, (weight, start_vertex, neighbor))
mst = []
while edges:
weight, u, v = heapq.heappop(edges)
if v not in visited:
visited.add(v)
mst.append((u, v, weight))
for neighbor, weight in graph[v].items():
if neighbor not in visited:
heapq.heappush(edges, (weight, v, neighbor))
return mst