📅  最后修改于: 2023-12-03 15:36:37.935000             🧑  作者: Mango
优先队列是一个常见的数据结构,它可以将元素按照优先级进行排序,并支持在队列的任意位置插入和删除元素。二叉堆是一种常用的实现优先队列的数据结构,它的时间复杂度对于大多数常见操作都是 O(log n)。
二叉堆是一种完全二叉树(即除了最后一层外,其它层的节点都是满的,最后一层的节点依次从左到右排列),它分为大根堆和小根堆两种。大根堆的每个节点都要大于等于它的子节点,小根堆则每个节点都要小于等于它的子节点。
我们可以用数组来表示二叉堆,其中数组下标与二叉树的节点一一对应。具体来说,对于下标为 i 的节点,它的左子节点下标为 2i,右子节点下标为 2i+1,它的父节点下标为 i/2(整数除法)。
下面是一个二叉堆的示例,其中橙色节点为根节点,红色为左右子节点。
插入元素的操作很简单,我们将元素添加到二叉堆的末尾,然后将它与它的父节点比较,如果它比父节点大(或小,根据要实现的是大根堆还是小根堆而定),则交换它们的位置,这样每次操作都能保证二叉堆的性质。
def insert(heap, val):
heap.append(val)
i = len(heap) - 1
while i > 1 and heap[i//2] < heap[i]:
heap[i], heap[i//2] = heap[i//2], heap[i]
i //= 2
# example usage
heap = []
insert(heap, 3)
insert(heap, 1)
insert(heap, 4)
insert(heap, 1)
insert(heap, 5)
print(heap) # Output: [5, 3, 4, 1, 1]
删除堆顶元素的操作也很简单,我们将堆顶元素(即数组的第一个元素)与最后一个元素交换位置,然后将它与它的子节点比较,如果它比子节点小(或大,根据要实现的是大根堆还是小根堆而定),则交换它们的位置,这样也能保证二叉堆的性质。最后再将堆顶元素移除即可。
def delete_top(heap):
if len(heap) == 1:
return heap.pop()
top = heap[1]
heap[1] = heap.pop()
i = 1
while True:
left = i * 2 if i * 2 < len(heap) else None
right = i * 2 + 1 if i * 2 + 1 < len(heap) else None
if left is None and right is None:
break
elif left is None:
max_child = right
elif right is None:
max_child = left
else:
max_child = left if heap[left] > heap[right] else right
if heap[i] < heap[max_child]:
heap[i], heap[max_child] = heap[max_child], heap[i]
i = max_child
else:
break
return top
# example usage
heap = []
insert(heap, 3)
insert(heap, 1)
insert(heap, 4)
insert(heap, 1)
insert(heap, 5)
print(delete_top(heap)) # Output: 5
print(heap) # Output: [4, 3, 1, 1]
获取堆顶元素的操作也很简单,只需要返回数组的第一个元素即可。
def get_top(heap):
if len(heap) > 1:
return heap[1]
return None
# example usage
heap = []
insert(heap, 3)
insert(heap, 1)
insert(heap, 4)
insert(heap, 1)
insert(heap, 5)
print(get_top(heap)) # Output: 5
二叉堆的时间复杂度如下:
由于二叉堆是一种完全二叉树,其空间复杂度是 O(n)。和其他一些实现优先队列的数据结构相比,它通常具有更好的常数因子,所以在实践中常常使用二叉堆来实现优先队列。