http://www.cnblogs.com/rocketfan/archive/2009/11/28/1612665.html
堆是常用的数据结构,经常用于实现优先队列中,huffman编码中的就用到了优先队列。
本质上就是用数组实现的完全二叉树保证父节点的关键码都大于或者等于其子节点的关键码(最大堆,反过来是最小堆),下图是一个最大堆示意。
那么在STL中有相应的堆算法,如判断一个序列是否为堆__is_heap,将一个序列建立为堆make_heap,向堆中插入元素push_heap,删除元素pop_heap,对堆排序等等sort_heap。个人认为STL的make_heap和pop_heap的实现并不是最好的,性能上也稍受影响。
就以建堆操作为例子吧,有两种方法:
- 就是用shift up的方法,所谓shift up就是前面的序列已经是堆了,再加入一个元素放到末尾,然后由底端向上通过和父节点比较交换到达合适的位置。这种方法也适合与push_heap也就是插入元素操作。用这种方法建堆复杂度是o(nlong(n))
- 更好的方案是采用shift down方法,这是假定我们已经知道要建堆区间的情况下。具体可以参考数据结构课本这方法的代价是o(n)的。
关于元素删除:
元素删除其实就是把堆顶端的元素删除,将堆末尾的元素赋值到堆顶端然后再利用shift down操作向下调整到合适的位置。
STL的算法实现中包括对一个区间建立堆结构和元素的删除都没有用shift down操作,统统用的是shift up(__push_heap),
比如说元素的删除,它会把堆顶元素删除,然后尝试着把从位置1到最后一个元素的位置都向上移动一位并且通过调整保持堆结构,最后
再次调用shift_up将尾元素向上移动到合适的位置。在网上查了下http://www.cppblog.com/guogangj/archive/2009/10/29/99729.html
其实就是下图这种算法,删除元素也是O(log(n))的代价,但是我觉得还是用shift down更直观,同时能够减少一定的比较移动的次数,虽然时间复杂度不变。
下图如果用shift down的话就是把8直接放到原来1的位置向下不断调整直到到达合适的位置。
shift up(__push_heap)的源代码如下:
//shift_up! 将位于first+holeIndex的值为value的元素shift up操作,最远直到
//first+topIndex位置
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)