一、python没有大顶堆的原因
Python没有内置大顶堆,是因为在实际使用中,大顶堆并不是那么常用。相比之下,小顶堆和普通的堆操作更具有广泛的应用场景,例如在排序算法、图论算法、贪心算法、动态规划等各种算法中都可以看到堆的身影。
此外,Python的设计哲学也与内置大顶堆不太相关。Python的优势在于其简单、易学、易用、可读性好等特点,而内置大顶堆对于一个通用的高级编程语言来说,显得过于专用和冗余。因此,Python通过标准库模块heapq提供了一组堆操作函数,使用者可以方便地根据需要构建小顶堆或者大顶堆,同时也避免了引入过多的不必要的数据类型和接口。
二、构造大顶堆的方法
堆是一种特殊的完全二叉树,使用数组存储二叉树时,若某个非叶子节点存储在下标为i的位置,其左右孩子节点分别存储在下标为2i+1和2i+2的位置。堆可以分为大顶堆和小顶堆,对大顶堆来说,任意非叶子节点不小于其左右孩子节点,对于小顶堆来说,任意非叶子节点不大于其左右孩子节点。若使用数组存储大顶堆,则满足:arr[i] >= arr[2i+1] && arr[i] >=arr[2i+2](i为非叶子节点的在数组中的下标)
基本思想:
从最后一个非叶子节点开始,逐一比较非叶子节点和其左右孩子节点根据比较结果交换节点因为交换可能导致孩子节点不再满足大顶堆的性质,所以需要对孩子节点进行调整。三、python实现大顶堆的方法
python中虽然没有内置大顶堆数据结构,但可以通过其他方法实现大顶堆。实现步骤如下:
1、创建MaxHeap类
初始化,存储最大元素数量、元素值计算函数、元素列表,当前元素数量。
class MaxHeap(object): def __init__(self, max_size, fn): self.max_size = max_size self.fn = fn self.items = [None] * max_size self.size = 0
2、获取大顶堆各个属性
def __str__(self): item_values = str([self.fn(self.items[i]) for i in range(self.size)]) return "Size: %d\nMax size: %d\nItem_values: %s\n" % (self.size, self.max_size, item_values)
3、检查大顶堆是否已满
@propertydef full(self): return self.size == self.max_size
4、添加元素
def add(self, item): if self.full: if self.fn(item) < self.value(0): self.items[0] = item self._shift_down(0) else: self.items[self.size] = item self.size += 1 self._shift_up(self.size - 1)
5、推出顶部元素
def pop(self): assert self.size > 0, "Cannot pop item! The MaxHeap is empty!" ret = self.items[0] self.items[0] = self.items[self.size - 1] self.items[self.size - 1] = None self.size -= 1 self._shift_down(0) return ret
6、元素上浮
def _shift_up(self, idx): assert idx < self.size, "The parameter idx must be less than heap's size!" parent = (idx - 1) // 2 while parent >= 0 and self.value(parent) < self.value(idx): self.items[parent], self.items[idx] = self.items[idx], self.items[parent] idx = parent parent = (idx - 1) // 2
7、元素下沉
def _shift_down(self, idx): child = (idx + 1) * 2 - 1 while child < self.size: if child + 1 < self.size and self.value(child + 1) > self.value(child): child += 1 if self.value(idx) < self.value(child): self.items[idx], self.items[child] = self.items[child], self.items[idx] idx = child child = (idx + 1) * 2 - 1 else: break
延伸阅读1:什么是堆数据结构
堆是一种完全二叉树,复习一下完全二叉树的定义,完全二叉树的形式是指除了最后一层之外,其他所有层的结点都是满的,而最后一层的所有结点都靠左边。教材上定义如下:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。