二叉堆(Binary heap)

二叉堆

堆的种类很多,在这儿我介绍一下二叉堆。二叉堆这个数据结构常用来实现优先队列和堆排序算法。堆这个名字很难听也很陌生,但是它真的很简单,因为它就是一颗完全二叉树,一般大二的时候都接触过。

完全二叉树

先回顾一下完全二叉树吧。我大二时候经常把完全二叉树和满二叉树弄混淆。满二叉数:除了叶节点其他节点都有左右孩子。完全二叉树可以是一个满二叉树,也可以是比满二叉树“少几个叶节点”的二叉树,不过这“少几个叶节点”是有条件的:必须从倒数第一个叶节点顺序减少。

完全二叉树的例子:

Correct nearly complete binary tree

这个就不是完全二叉树:

Incorrect case, pic. 1

这个也不是:

Incorrect case, pic. 2

完全二叉树的高度是:log n.

有两种二叉堆:大顶堆和小顶堆。大顶堆的父节点存储比孩子节点大的值。小顶堆情况刚好相反。

小顶堆

每个节点的值小于或等于左右孩子节点的值

Min heap illustration

大顶堆

每个节点的值大于或等于左右孩子节点的值

Max heap illustration

用数组表示二叉堆

堆是二叉树,以为这可用用链表存储堆元素。用链表存储需要额外的空间存储节点之间的连接信息,所以相比用数组存储浪费存储空间。并且堆是完全二叉树,刚好适合用数组存储。

堆与数组的映射

从上到下一层一层地把堆元素存储在数组中。如下图:

有一点很重要,我们可以用数组的索引来确定父结点和孩子节点的相对关系,索引(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

向堆中插入一个元素

插入算法

  1. 在数组末尾添加一个元素
  2. 这时堆的性质会破坏。插入节点和父结点比较,如果顺序错误,交换之。

往下面这个堆中插入元素-2

添加到数组的末尾:

堆性质破坏:

为此,需要将新元素向上提升, 将它和父结点交换:

现在仍然不满足堆的要求:

继续提升:

插入完成。

复杂度分析:

插入操作的复杂度是 O(h), h是堆的高度。 因此O(h) = O(log n),n是堆的元素数。

从堆中删除最小值

删除算法

从下面这个堆中删除最小值:

将数组最后一个元素放到堆根(root)上,堆元素个数减少1:

堆性质破坏:

跟节点和左右孩子节点中最小者交换:

交换后仍然不满足堆的要求:

按照上面规则继续交换:

复杂度分析

和插入算法的复杂对一样:.O(h) = O(log n),h为堆的高度,n为元素个数。

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

稍后的文章我会用C语言实现下小顶堆。




没有更多推荐了,返回首页