什么是堆
堆是一种完全二叉树
- 最大堆:对于每个非叶子节点,都比他的两个孩子大,称为最大堆最大堆特性,最大堆里的根节点往往是最大值
- 最小堆:和最大堆相反,每个非叶子节点,两个孩子都比他大
堆的表示:用二叉树表示
堆提供了很有限的几个操作
1.插入新的值,插入比较麻烦的就是需要维持对的特性,需要sift_up操作
2.获取并移除根节点的值,每次我们都可以获取最大值和最小值,这个时候需要把底层最右边的节点值替换到root 之后siftdown操作
#实现一个定长的数组arroy
class Array(object):
#初始化
def __init__(self,size = 32):
#
self._size = size
#长度为size,value全为None的列表
self._items = [None] * size
#通过[]获取value
def __getitem__(self,index):
return self.items[index]
#下标赋值
def __setitem__(self,index,value):
self._items[index] = value
#返回长度
def __len__(self):
return self._size
#清除数组
def cleor(self,value = None):
for i in range(len(self.items)):
self._items[i] = value
#遍历数组
def __iter__(self):
for item in self._items:
yield item
################################################################
#实现一个堆排序
################################################################
class MaxHeap(object):
#初始化
def __init__(self,maxsize = None):
#定义一个最大长度
self.maxsize = maxsize
#定义个数
self._count = 0
#新建一个数组
self._elements = Array(maxsize)
#长度
def __len__(self):
#直接返回元素的个数
return self._count
#添加方法
def add(self,value):
#首先判断换是否超出了最大长度
if self.count >= self.maxsize:
raise Exception('full')
#把值赋给节点
self._elements[self._count] = value
#长度加一
self._count += 1
#调用silfup方法
self.silfup(self._count - 1)
#判断位置方法
def _silfup(self, ndx):
#判断换长度
if ndx > 0 :
#计算上一个节点的下标
parent = ((ndx-1) / 2)
#判断子节点大于父节点
if self._elements[ndx] > self._elements[parent]:
#交换值
self._elements[ndx],self._elements[parent] = self._elements[parent],self._elements[ndx]
#递归在进行比较
self._silfup(parent)
#删除根节点
def extract(self):
#先判断是否还有值
if self._count <= 0:
raise Exception('empty')
#取出根节点
value = self._elements[0]
#长度减一
self._count -= 1
#把最后一个节点上的值,赋值给根节点
self._elements[0] = self._elements[self._count]
#调用_siftdown 函数
self._siftdown(0)
#返回根节点的值
return value
#通过siftdown的方法满足最大堆的特点
def _siftdown(self,ndx):
#计算左孩子的下标
left = 2 * ndx + 1
#3计算右孩子的下标
right = 2 * ndx + 2
langest = ndx
#首先左节点下标要小于当前的数组的长度,其次左孩子大于根节点,再其次左孩子大于右孩子
if (left < self._count and
self._elements[left] >= self._elements[langest] and
self._elements[left] >= self._elements[right]):
#把值左孩子的下标,赋值给langest
langest = left
#右孩子下标小于数组的长度,其次右孩子大于左孩子
elif right < self._count and self._elements[right] >= self._elements[langest]:
#把右孩子的下标赋给langest
langest = right
#当左孩子,或者是右孩子的不等于根下标
if langest != ndx:
#根节点和左孩子或者右孩子交换位置
self._elements[ndx],self._elements[langest] = self._elements[langest],self._elements[ndx]
#递归调用siftdown方法,,从当前节点开始重新判断
self._siftdown(langest)