96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
|
"""
|
|||
|
堆:是一种满足特定条件的完全二叉树,主要分为
|
|||
|
- [大顶堆]:任意节点的值 >= 其子节点
|
|||
|
- [小顶堆]:任意节点的值 <= 其子节点
|
|||
|
|
|||
|
堆作为完全二叉树的一个特例,具有以下特性。
|
|||
|
|
|||
|
- 最底层节点靠左填充,其他层的节点都被填满。
|
|||
|
- 我们将二叉树的根节点称为“堆顶”,将底层最靠右的节点称为“堆底”。
|
|||
|
- 对于大顶堆(小顶堆),堆顶元素(根节点)的值分别是最大(最小)的。
|
|||
|
|
|||
|
实际上,堆通常用于实现优先队列,大顶堆相当于元素按从大到小的顺序出队的优先队列,
|
|||
|
所以堆可以使用数组来保存。
|
|||
|
|
|||
|
由于是完全二叉树,除堆底外,每个节点都有两个子节点,所以在数组中很容易确定子节点和父节点的位置
|
|||
|
假设父节点的下标 p, 则其左右子节点的下标为 2p 和 2p+1。
|
|||
|
|
|||
|
注意下标0不能存数据因为,因为 2p == 0
|
|||
|
"""
|
|||
|
|
|||
|
|
|||
|
# 小顶堆,小顶堆添加数据时,小数据要向上冒到正确的位置
|
|||
|
class Heap:
|
|||
|
def __init__(self):
|
|||
|
self.size = 0
|
|||
|
self.data = [0]
|
|||
|
|
|||
|
# 获取父节点下标
|
|||
|
def parent(self, c: int):
|
|||
|
return c >> 1
|
|||
|
|
|||
|
def left_child(self, c: int):
|
|||
|
return c << 2
|
|||
|
|
|||
|
def right_child(self, c: int):
|
|||
|
return c << 2 + 1
|
|||
|
|
|||
|
def push(self, value):
|
|||
|
self.data.append(value)
|
|||
|
self.size += 1
|
|||
|
# 添加到堆底,需要向上冒泡
|
|||
|
self.move_up(self.size)
|
|||
|
|
|||
|
# 小数据冒泡
|
|||
|
def move_up(self, c: int):
|
|||
|
while True:
|
|||
|
p = self.parent(c)
|
|||
|
if p <= 0:
|
|||
|
break
|
|||
|
if self.data[c] < self.data[p]:
|
|||
|
self.data[c], self.data[p] = self.data[p], self.data[c]
|
|||
|
c = p
|
|||
|
|
|||
|
# 删除堆底的最后一个元素
|
|||
|
def pop(self):
|
|||
|
return self.data.pop()
|
|||
|
|
|||
|
# 删除小顶堆中的最小值,也就是根节点
|
|||
|
def pop_min(self):
|
|||
|
if 0 == self.size:
|
|||
|
return None
|
|||
|
|
|||
|
if 1 == self.size:
|
|||
|
# 只有一个元素,直接弹出
|
|||
|
self.size -= 1
|
|||
|
return self.data.pop()
|
|||
|
|
|||
|
self.data[1], self.data[self.size] = self.data[self.size], self.data[1]
|
|||
|
val = self.pop()
|
|||
|
self.move_down(1)
|
|||
|
return val
|
|||
|
|
|||
|
# 大数据下沉
|
|||
|
def move_down(self, c: int):
|
|||
|
while True:
|
|||
|
lc = self.left_child(c)
|
|||
|
if lc > self.size:
|
|||
|
# 没有左子节点,故而当然没有右子节点
|
|||
|
break
|
|||
|
|
|||
|
mc = self.min_child(c)
|
|||
|
if self.data[c] > self.data[mc]:
|
|||
|
self.data[c], self.data[mc] = self.data[mc], self.data[c]
|
|||
|
|
|||
|
c = mc
|
|||
|
|
|||
|
# 获取两个子节点中的较小节点的下标
|
|||
|
def min_child(self, c):
|
|||
|
lc, rc = self.left_child(c), self.right_child(c)
|
|||
|
if rc > self.size:
|
|||
|
return lc
|
|||
|
if self.data[lc] > self.data[rc]:
|
|||
|
return rc
|
|||
|
else:
|
|||
|
return lc
|