python数据结构学习笔记-2016-11-30-01-堆
来源:互联网 发布:阿尔泰神族 知乎 编辑:程序博客网 时间:2024/05/10 19:14
13.4 堆
堆(heap)是一个完全二叉树,其结点组织是基于各自结点的数据域。它有两个重要的变种——最大堆和最小堆。
最大堆(max-heap),具有称为堆序性质(heap order property)。对于其任意一个内结点而言,该结点处的值均大于其两个子结点的值。
最小堆(min-heap),则具有相反的堆序性质,对于其任意一个内结点而言,该结点处的值均小于其两个子结点的值。
13.4.1 定义
插入操作
向堆中插入新值,堆序性质和堆形性质(heap shape property,即保持其作为完全二叉树的性质)都要保持。
例如分别向如下两个最大堆插入元素90和元素41。
我们从堆的底部开始,先创建新结点,再将之添加到堆中,再与其父结点比较,若大于父结点,则两者互换,重复此过程,直至小于父结点为止。向上移动的过程就称为sift-up过程。
提取
从堆中提取元素,即从堆中删除元素。通常,我们是从最大堆中提取最大的元素,从最小堆中提取最小的元素。例如从如下最大堆中提取最大值。
首先是复制根结点,其次是最底层最右边的元素,复制到根结点中,然后与其子结点比较,若小于子结点,则将其与较大的子结点互换,重复此过程,直至其到达叶结点或者碰到比其更小的结点为止。向下移动的过程称为sift-down。
13.4.2 实现
虽然堆本质是二叉树,但是几乎不用动态链式结构来实现,其原因是堆涉及到的向上移动和向下移动,即sift-up和sift-down过程。我们使用数组或者动态数组(python列表)来实现堆。
访问结点
由于堆是完全二叉树,其中不会有空洞致使内结点缺失。因此可以将根结点放入数组中的索引为0的位置,其两个子结点则分别放入索引为1和2的位置,依次类推。则对于数组中索引为i的位置储存的结点,有
父结点的索引为 parent = (i - 1) / 2
左子结点的索引为 left = 2 * i + 1
右子结点的索引为right = 2 * i + 2
判读一个结点是否有子结点,则可计算其假设左子结点和右子结点的索引值,若没有超出数组容量,则相应的子结点存在,若超出数组容量,则相应的子结点就不存在。
#-*-coding: utf-8-*-# 用数组实现最大堆class MaxHeap(object): # 创建最大堆,使用最大容量为maxSize的数组 def __init__(self, maxSize): self._elements = Array(maxSize) self._count = 0 # 当前最大堆中的结点个数 # 最大堆中的结点数目 def __len__(self): return self._count # 最大堆的容量 def capacity(self): return len(self._elements) # 向最大堆中添加元素 def add(self, value): assert self._count < self.capacity(), "Cannot add to a full heap." self._elements[self._count] = value self._count += 1 self._siftUp(self._count-1) # sift-up过程 # 从最大堆中提取最大元素,即根结点 def extract(self): assert self._count > 0, "Cannot extract from an empty heap." value = self._elements[0] self._count -= 1 self._elements[0] = self._elements[self._count] self._siftDown(0) # sift-down过程 # sift-up过程 def _siftUp(self, ndx): if ndx > 0: parent = ndx / 2 if self._elements[ndx] > self._elements[parent]: self._elements[ndx], self._elements[parent] = self._elements[parent], self._elements[ndx] self._siftUp(parent) # sift-down过程 def _siftDown(self, ndx): left = 2 * ndx + 1 right = 2 * ndx + 2 # 找出两子结点中的较大者 largest = ndx if left < count and self._elements[left] >= self._elements[largest]: largest = left elif right < count and self._elements[right] >= self._elements[largest]: largest = right # 如果ndx结点的值小于两子结点中的较大者,即largest,则将两者互换 if largest != ndx: self._elements[ndx], self._elements[largest] = self._elements[largest], self._elements[ndx] self._siftDown(largest)
- python数据结构学习笔记-2016-11-30-01-堆
- python数据结构学习笔记-2016-12-03-01-堆排序
- python数据结构学习笔记-2016-11-11-01-递归
- python数据结构学习笔记-2016-11-07-01-双链表
- python数据结构学习笔记-2016-11-09-01-文本编辑器
- python数据结构学习笔记-2016-11-14-01-散列表
- python数据结构学习笔记-2016-11-20-01-直方图ADT
- python数据结构学习笔记-2016-11-23-01-归并排序
- python数据结构学习笔记-2016-11-24-01-快速排序
- python数据结构学习笔记-2016-11-27-01-二叉树
- python数据结构学习笔记-2016-11-28-01-表达式树
- 学习笔记 数据结构 堆结构
- python学习笔记-数据结构
- python学习笔记--堆(heap)
- python数据结构学习笔记-2016-10-15-01-矩阵ADT
- python数据结构学习笔记-2016-10-17-01-集合
- python数据结构学习笔记-2016-10-21-01-复杂度分析
- python数据结构学习笔记-2016-10-23-01-搜索
- 普通赋值和引用赋值
- PAT_乙级 1021 个位数统计
- - (void)loadView方法
- Tensorflow 离线安装跳坑总结
- Java中的StringBuffer和Stringbuider
- python数据结构学习笔记-2016-11-30-01-堆
- 邮件发送以及javax.mail.NoSuchProviderException: Unable to locate provider for protocol: smtp解决方案
- 无线安全专题_攻击篇--干扰通信
- Elasticsearch使用中遇到的一些问题及相应解决方法
- android google map 入门 四
- python常用函数(一)
- Destroying Array
- Video标签的问题
- lintcode,复制带随机指针的链表