""" 堆:是一种满足特定条件的完全二叉树,主要分为 - [大顶堆]:任意节点的值 >= 其子节点 - [小顶堆]:任意节点的值 <= 其子节点 堆作为完全二叉树的一个特例,具有以下特性。 - 最底层节点靠左填充,其他层的节点都被填满。 - 我们将二叉树的根节点称为“堆顶”,将底层最靠右的节点称为“堆底”。 - 对于大顶堆(小顶堆),堆顶元素(根节点)的值分别是最大(最小)的。 实际上,堆通常用于实现优先队列,大顶堆相当于元素按从大到小的顺序出队的优先队列, 所以堆可以使用数组来保存。 由于是完全二叉树,除堆底外,每个节点都有两个子节点,所以在数组中很容易确定子节点和父节点的位置 假设父节点的下标 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