二叉堆
堆的种类很多,在这儿我介绍一下二叉堆。二叉堆这个数据结构常用来实现优先队列和堆排序算法。堆这个名字很难听也很陌生,但是它真的很简单,因为它就是一颗完全二叉树,一般大二的时候都接触过。
完全二叉树
先回顾一下完全二叉树吧。我大二时候经常把完全二叉树和满二叉树弄混淆。满二叉数:除了叶节点其他节点都有左右孩子。完全二叉树可以是一个满二叉树,也可以是比满二叉树“少几个叶节点”的二叉树,不过这“少几个叶节点”是有条件的:必须从倒数第一个叶节点顺序减少。
完全二叉树的例子:

这个就不是完全二叉树:
这个也不是:
完全二叉树的高度是:log n.
堆
有两种二叉堆:大顶堆和小顶堆。大顶堆的父节点存储比孩子节点大的值。小顶堆情况刚好相反。
小顶堆
每个节点的值小于或等于左右孩子节点的值

大顶堆
每个节点的值大于或等于左右孩子节点的值
用数组表示二叉堆
堆是二叉树,以为这可用用链表存储堆元素。用链表存储需要额外的空间存储节点之间的连接信息,所以相比用数组存储浪费存储空间。并且堆是完全二叉树,刚好适合用数组存储。
堆与数组的映射
从上到下一层一层地把堆元素存储在数组中。如下图:
有一点很重要,我们可以用数组的索引来确定父结点和孩子节点的相对关系,索引(index)计算如下:
i节点(index=i)的左孩子的索引:Left(i) = 2 * i + 1
i节点(index=i)的右孩子的索引:Right(i) = 2 * i + 2
i节点(index=i)的父节点的索引:Parent(i) = 2 * i + 2
向堆中插入一个元素
插入算法
- 在数组末尾添加一个元素
- 这时堆的性质会破坏。插入节点和父结点比较,如果顺序错误,交换之。
例
往下面这个堆中插入元素-2
添加到数组的末尾:
堆性质破坏:
现在仍然不满足堆的要求:
插入完成。
复杂度分析:
插入操作的复杂度是 O(h), h是堆的高度。 因此O(h) = O(log n),n是堆的元素数。
从堆中删除最小值
删除算法
从下面这个堆中删除最小值:
将数组最后一个元素放到堆根(root)上,堆元素个数减少1:
堆性质破坏:
跟节点和左右孩子节点中最小者交换:
交换后仍然不满足堆的要求:
按照上面规则继续交换:
复杂度分析
和插入算法的复杂对一样:.O(h) = O(log n),h为堆的高度,n为元素个数。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
稍后的文章我会用C语言实现一下小顶堆。