优先队列是一种特殊的队列,每次取出的元素总是“最优先”的那个。最小堆是实现优先队列的常用方法,能高效地找到最小值。下面带你轻松了解最小堆的原理和用法!
普通队列是“先进先出”,而优先队列是“优先级高的先出”。最小堆是一种二叉树结构,能保证每次取出的都是最小值。
# 完全二叉树简介:
# 完全二叉树是一种特殊的二叉树结构,除了最后一层外,每一层的节点数都达到最大,最后一层的节点都集中在左侧。
# 这种结构保证了树的高度最小,便于用数组顺序存储,父子节点下标有简单的数学关系。
# 最小堆正是利用完全二叉树的结构高效实现的。
# 算法执行原理:
# 最小堆是一种完全二叉树结构,能高效维护一组元素的最小值。
# 插入元素时,将新元素放到堆尾,然后不断与父节点比较并“上浮”,直到满足父节点小于等于自己的最小堆性质。
# 弹出最小值时,将堆顶元素移除,用最后一个元素补到堆顶,然后不断与子节点比较并“下沉”,直到满足最小堆性质。
# 这样可以保证每次取出的都是当前所有元素中的最小值,插入和删除的时间复杂度都是O(log n)。
# 定义最小堆类
class MinHeap:
# 初始化方法,创建一个空列表用于存储堆元素
def __init__(self):
self.data = []
# 向堆中插入新元素
def push(self, val):
# 将新元素添加到堆的末尾
self.data.append(val)
# 获取新元素的索引
i = len(self.data) - 1
# 上浮操作,保证最小堆性质
while i > 0:
# 计算父节点索引
parent = (i - 1) // 2
# 如果当前节点小于父节点,则交换
if self.data[i] < self.data[parent]:
self.data[i], self.data[parent] = self.data[parent], self.data[i]
# 更新索引为父节点,继续上浮
i = parent
else:
# 如果不需要交换,结束上浮
break
# 弹出堆顶元素(最小值)
def pop(self):
# 如果堆为空,返回None
if not self.data:
return None
# 记录堆顶元素
min_val = self.data[0]
# 弹出最后一个元素
last = self.data.pop()
# 如果堆不为空,将最后一个元素放到堆顶,并下沉调整
if self.data:
self.data[0] = last
i = 0
n = len(self.data)
# 下沉操作,保证最小堆性质
while True:
# 计算左子节点索引
left = 2 * i + 1
# 计算右子节点索引
right = 2 * i + 2
# 记录当前最小值索引
smallest = i
# 如果左子节点存在且小于当前节点,更新最小值索引
if left < n and self.data[left] < self.data[smallest]:
smallest = left
# 如果右子节点存在且小于当前最小值,更新最小值索引
if right < n and self.data[right] < self.data[smallest]:
smallest = right
# 如果最小值索引没有变化,结束下沉
if smallest == i:
break
# 交换当前节点与最小子节点
self.data[i], self.data[smallest] = self.data[smallest], self.data[i]
# 更新索引为最小子节点,继续下沉
i = smallest
# 返回堆顶元素
return min_val
# 使用示例
# 创建最小堆对象
heap = MinHeap()
# 向堆中依次插入元素5, 2, 8, 1
for x in [5, 2, 8, 1]:
heap.push(x)
# 打印当前堆的内容,应该为[1, 2, 8, 5]
print(heap.data) # 输出[1, 2, 8, 5]
# 弹出堆顶元素(最小值),应该为1
print(heap.pop()) # 输出1
# 打印弹出后的堆内容,应该为[2, 5, 8]
print(heap.data) # 输出[2, 5, 8]
heap = MinHeap()[]heap.push(5)[5]heap.push(2)[2, 5]heap.push(8)[2, 5, 8]heap.push(1)[1, 2, 8, 5]
print(heap.data)[1, 2, 8, 5]heap.pop()[2, 5, 8]
print(heap.data)[2, 5, 8]最小堆让我们能高效地管理和获取“最小值”,是很多算法和系统的基础工具。学会它,你就能轻松应对各种优先级相关的问题!