python没有大顶堆的原因:在实际使用中,大顶堆并不是那么常用。此外,Python的设计哲学也与内置大顶堆不太相关,Python的优势在于其简单、易学、易用、可读性好等特点,而内置大顶堆对于一个通用的高级编程语言来说,显得过于专用和冗余。
一、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、检查大顶堆是否已满
@property
def 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 层所有的结点都连续集中在最左边,这就是完全二叉树。