先引用 《STL 源码剖析》(作者: 侯捷)的原话:
heap 并不属于 STL 的容器组件, 它是一个幕后英雄 ,扮演 priority queue 的助手。
binary heap 是一种 完全二叉树(completely binary tree),也就是说,整棵 binary tree
除了最底层的叶子节点以外,都是填满的 。而最底层的叶子节点由左到右又不得有空隙。
完全二叉树没有任何的节点漏洞,这带来了极大的好处是,允许我们以array 来存储所有的节点。
根据元素的排列顺序,heap 可以分为 max-heap 和 min-heap 两种。
原话结束。
但是,由于 array 并不能实现动态增长,所以,用了vector 作为完全二叉树的表达方式。
主要实现的函数是:
push_heap();
pop_heap();
make_heap();
sort_heap();
#include<iostream>
#include<vector>
using namespace std;
namespace Hheap
{
template<class random_iterator>
void push_heap(random_iterator first, random_iterator last)
{
/*其实就是一个上溯的过程,这里先用迭代器“榨汁机”,榨取类型*/
typedef typename iterator_traits<random_iterator> :: value_type value_type;
typedef typename iterator_traits<random_iterator> :: difference_type difference_type;
if((last- 1)<=first)
return;
value_type value = *(last -1);
// index of (last -1)
difference_type hole_index= (last -1) -first ;
//parents of (last -1 )
difference_type parent = (hole_index-1)/2;
//上溯的结束条件是 洞口小于零 或者 不如父节点的值大
while(hole_index > 0 && *(first+ parent)<value)
{
*(first + hole_index) = *(first + parent) ;
hole_index = parent;
parent = (hole_index-1)/2;
}
*(first + hole_index) = value;
}
template<class random_iterator >
void pop_heap(random_iterator first , random_iterator last)
{
/*取出最大值的过程比较麻烦,包含着一个 下溯,下溯完成又存在一个上溯*/
typedef typename iterator_traits<random_iterator> :: difference_type difference_type;
typedef typename iterator_traits<random_iterator> :: value_type value_type;
value_type value = *first;
//index of first
difference_type hole_index = 0;
// left child
difference_type left_child = hole_index*2+1;
// right child
difference_type right_child = left_child +1 ;
while( right_child <(last - first))
{
if(*(first + right_child) < *(first + left_child) )
{
*(first + hole_index) = *(first + left_child);
hole_index = left_child;
}
else
{
*(first + hole_index) = *(first + right_child);
hole_index = right_child;
}
left_child = hole_index*2+1;
right_child = left_child +1;
}
// 如果还有左孩子 ,那么单独处理
if(left_child < (last - first))
{
*(first + hole_index) = *(first + left_child);
hole_index = left_child; //更改洞口 到最后一个。
}
*(first + hole_index) = *(last - 1);
// 再执行一次上溯
push_heap(first , first + hole_index +1);
*(last -1) = value;
}
template<class random_iterator >
void sort_heap(random_iterator first , random_iterator last)
{
/*不断的执行 pop_heap 将最大值放到末尾 然后,去掉最后一个数,再次执行pop_heap
*/
if(last - first <=1)
return ;
while(last - first >1)
pop_heap(first,last--);
}
template<class random_iterator >
void make_heap(random_iterator first ,random_iterator last)
{
typedef typename iterator_traits<random_iterator > ::difference_type difference_type;
typedef typename iterator_traits<random_iterator > :: value_type value_type;
if(last - first <= 1)
return ;
difference_type i = 2;
while((first +i )<=last)
{
Hheap::push_heap(first , (first+i) );
++i;
}
}
template<class Sequence >
void print(Sequence& c)
{
for(auto iter= c.begin() ;iter !=c.end();iter ++)
cout<<*(iter)<<" ";
cout<<endl;
}
}; //namespace end
int main()
{
std::vector<int > v;
v.push_back(4);
v.push_back(6);
v.push_back(3);
v.push_back(2);
v.push_back(8);
v.push_back(9);
Hheap::make_heap(v.begin(),v.end() ); //建立堆
Hheap::print(v); //打印堆
v.push_back(56);
Hheap::push_heap(v.begin(),v.end()); //压入堆,上溯建立合法的堆
Hheap::print(v); //打印堆
Hheap::pop_heap(v.begin(),v.end()); //将最大值取出,先下溯 再上溯 建立合法的堆
Hheap::print(v); //打印堆
v.pop_back();
Hheap::sort_heap(v.begin(),v.end()); //对堆进行重新排序
Hheap::print(v); //打印堆
}