经过在上一个版本的修改,添加了STL风格的Heap,在这里要感谢优快云论坛中那些帮助过我的人。 代码如下(heap.h) /* * 文件:heap.h * 描述:堆得实现,添加了比较和交换Functor,以便于扩展。 * 同时添加了STL风格的堆,可以同时使用vector或deque作为容器。 * 作者:BourneID * 日期:2010-5-21 * 版本:1.3 */ #ifndef __HEAP__ #define __HEAP__ #include <stdexcept> #include <iostream> #include <vector> #include <ctime> namespace MyHeap{ //默认比较Functor template<class HeapNode> class DefaultCmpOpr{ public: inline bool operator()(const HeapNode& lhs,const HeapNode& rhs){ return lhs>rhs; } }; //默认交换操作函数对象 template<class HeapNode> class DefaultSwapDo{ public: inline void operator()(HeapNode& lhs,HeapNode& rhs){::swap(lhs,rhs);} }; /****************************节点访问函数****************************/ //父亲节点 inline int Parent(const int& index){return (index-1)/2;} //左儿子 inline int Left(const int& index){return 2*index+1;} //右儿子 inline int Right(const int& index){return 2*index+2;} /****************************堆调整函数**************************/ //下浮节点 template<class HeapNode,class CmpOpr,class SwapDo> void HeapDown(std::vector<HeapNode>& heap,int index,CmpOpr opr,SwapDo sd); //上浮节点 template<class HeapNode,class CmpOpr,class SwapDo> void HeapUp(std::vector<HeapNode>& heap,int index,CmpOpr opr,SwapDo sd); /****************************堆相关操作*************************/ //出堆 template<class HeapNode,class CmpOpr,class SwapDo> void PopHeap(std::vector<HeapNode>& heap,CmpOpr opr,SwapDo sd); //入堆 template<class HeapNode,class CmpOpr,class SwapDo> void PushHeap(std::vector<HeapNode>& heap,const HeapNode& newNode,CmpOpr cmp,SwapDo sd); //生成堆 template<class HeapNode,class CmpOpr,class SwapDo> void MakeHeap(std::vector<HeapNode>& heap,CmpOpr cmp,SwapDo sd); //判断是否是推 template<class HeapNode,class CmpOpr> bool IsHeap(std::vector<HeapNode>& heap,CmpOpr cmp); /*******************************STL风格Heap********************************/ /****************************节点访问函数****************************/ //访问父亲节点,如果没有,返回边界 template<class RandomItr> inline RandomItr Parent(RandomItr begin,RandomItr end,RandomItr index){ int idxInt=(index-begin-1)/2; if(idxInt<0){//返回边界 return end; }else{ return begin+(index-begin-1)/2; } } //访问左儿子,如果没有,返回边界 template<class RandomItr> inline RandomItr Left(RandomItr begin,RandomItr end,RandomItr index){ int idxInt=(index-begin)*2+1; if(idxInt>=end-begin){//越界 return end;//返回边界 }else{ return begin+idxInt; } } //访问右儿子,如果没有,返回边界 template<class RandomItr> inline RandomItr Right(RandomItr begin,RandomItr end,RandomItr index){ int idxInt=(index-begin)*2+2; if(idxInt>=end-begin){//越界 return end;//返回边界 }else{ return begin+(index-begin)*2+2; } } /****************************STL风格 堆调整函数**************************/ //堆上浮 template<class RandomItr,class CmpOpr,class SwapDo> void HeapUp(RandomItr begin,RandomItr end,RandomItr index,CmpOpr cmp,SwapDo sd); //堆下沉 template<class RandomItr,class CmpOpr,class SwapDo> void HeapDown(RandomItr begin,RandomItr end,RandomItr index,CmpOpr cmp,SwapDo sd); /****************************STL风格堆相关操作*************************/ //出堆 template<class RandomItr,class CmpOpr,class SwapDo> void PopHeap(RandomItr begin,RandomItr end,CmpOpr cmp,SwapDo sd); //入堆 template<class RandomItr,class CmpOpr,class SwapDo> void PushHeap(RandomItr begin,RandomItr end,CmpOpr cmp,SwapDo sd); //制作堆 template<class RandomItr,class CmpOpr,class SwapDo> void MakeHeap(RandomItr begin,RandomItr end,CmpOpr cmp,SwapDo sd); //判断是否是堆 template<class RandomItr,class CmpOpr> bool IsHeap(RandomItr begin,RandomItr end,CmpOpr cmp); //堆排序 template<class RandomItr,class CmpOpr, class SwapDo> void SortHeap(RandomItr begin,RandomItr end, CmpOpr cmp,SwapDo sd); /******************************以下为使用Demo******************************/ //测试堆 void TestHeap(){ { ::srand(::time(NULL)); //测试PushPop和IsHeap using namespace std; std::vector<int> heap; const int N=10; const int MAX=100; for(int i=0;i<N;++i){ PushHeap(heap,rand()%MAX,DefaultCmpOpr<int>(),DefaultSwapDo<int>()); } cout<<"******************************测试PushPop和IsHeap******************************"<<endl; cout<<"Random Heap:"; copy(heap.begin(),heap.end(),ostream_iterator<int>(cout," ")); cout<<endl<<(IsHeap(heap,DefaultCmpOpr<int>())?"Is Heap":"Not a Heap")<<endl; } //测试MakeHeap和PopHeap { ::srand(::time(NULL)); using namespace std; std::vector<int> heap; const int N=10; const int MAX=100; for(int i=0;i<N;++i){ heap.push_back(rand()%MAX); } MakeHeap(heap,DefaultCmpOpr<int>(),DefaultSwapDo<int>()); for(int i=0;i<N/2;++i){ PopHeap(heap,DefaultCmpOpr<int>(),DefaultSwapDo<int>()); } cout<<"*************************测试MakeHeap和PopHeap************************"<<endl; cout<<"Random Heap:"; copy(heap.begin(),heap.end(),ostream_iterator<int>(cout," ")); cout<<endl<<(IsHeap(heap,DefaultCmpOpr<int>())?"Is Heap":"Not a Heap")<<endl; } } //测试STL堆 void TestSTLHeap(){ using namespace std; //初始化 std::vector<int> heap; //std::deque<int> heap;//双向队列也可以 const int N=11; const int MAX=100; for(int i=0;i<N;++i){ heap.push_back(rand()%MAX); } //输出初始化数据 std::copy(heap.begin(),heap.end(),std::ostream_iterator<int>(cout," ")); cout<<endl; //制作堆 MakeHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>()); cout<<"Heap "<<endl; std::copy(heap.begin(),heap.end(),std::ostream_iterator<int>(cout," ")); bool is=IsHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>()); if(is){ cout<<"/nThis a heap!"<<endl; }else{ cout<<"/nThis is not a heap!"<<endl; } //测试堆排序 SortHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>()); cout<<"Sorted "<<endl; copy(heap.begin(),heap.end(),ostream_iterator<int>(cout," ")); cout<<endl; //测试PushHeap和PopHeap heap.clear(); for(int i=0;i<N;++i){ heap.push_back(rand()%MAX); PushHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>()); } for(int i=0;i<N/2;++i){ PopHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>()); heap.pop_back(); } cout<<"The new heap created by pushing and popping!"<<endl; copy(heap.begin(),heap.end(),ostream_iterator<int>(cout," ")); cout<<endl; } } template<class HeapNode,class CmpOpr> bool MyHeap::IsHeap(std::vector<HeapNode>& heap,CmpOpr cmp){ if(heap.size()==0 && heap.size()==1){ return true; } for(int i=heap.size()/2-1;i>=0;--i){ if(cmp(heap[i],heap[Left(i)])){ return false; } if(Right(i)<heap.size() && cmp(heap[i],heap[Right(i)])){//右儿子存在,且比左儿子更适合 return false; } } return true; } template<class HeapNode,class CmpOpr,class SwapDo> void MyHeap::HeapUp(std::vector<HeapNode>& heap,int index,CmpOpr cmp,SwapDo sd){ int par=Parent(index); while(index>=0 && cmp(heap[par],heap[index])){ sd(heap[par],heap[index]); index=par; par=Parent(index); } } template<class HeapNode,class CmpOpr,class SwapDo> void MyHeap::PopHeap(std::vector<HeapNode>& heap,CmpOpr opr,SwapDo sd){ if(heap.empty()){ return; } sd(heap[0],heap[heap.size()-1]); heap.pop_back();//将堆中的最后一个元素去除 //调整堆 HeapDown(heap,0,opr,sd); } template<class HeapNode,class CmpOpr,class SwapDo> void MyHeap::PushHeap(std::vector<HeapNode>& heap,const HeapNode& newNode,CmpOpr cmp,SwapDo sd){ heap.push_back(newNode); HeapUp(heap,heap.size()-1,cmp,sd); } template<class HeapNode,class CmpOpr,class SwapDo> void MyHeap::HeapDown(std::vector<HeapNode>& heap,int index,CmpOpr opr,SwapDo sd){ int son=Left(index); while(son<heap.size()){ if(son+1<heap.size() && opr(heap[son],heap[son+1])){//右儿子存在 ++son; } if(opr(heap[index],heap[son])){ sd(heap[index],heap[son]); index=son; son=Left(index); }else{//找到合适位置 return; } } } template<class HeapNode,class CmpOpr,class SwapDo> void MyHeap::MakeHeap(std::vector<HeapNode>& heap,CmpOpr cmp,SwapDo sd){ for(int i=heap.size()/2-1;i>=0;--i){ HeapDown(heap,i,cmp,sd); } } /****************************************STL风格************************************/ template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::HeapUp(RandomItr begin,RandomItr end, RandomItr index, CmpOpr cmp,SwapDo sd){ RandomItr parItr=Parent(begin,end,index); while(parItr!=end && cmp(*parItr,*index)/*注意*/){ sd(*index,*parItr); index=parItr; parItr=Parent(begin,end,index); } } template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::HeapDown(RandomItr begin,RandomItr end, RandomItr index, CmpOpr cmp,SwapDo sd){ RandomItr sonItr=Left(begin,end,index); while(sonItr!=end){ //找到合适的儿子 if(sonItr+1!=end && cmp(*sonItr,*(sonItr+1))/*注意*/){ ++sonItr; } if(cmp(*index,*sonItr)/*注意*/){ sd(*sonItr,*index);//do after swapping //继续向下寻找 index=sonItr; sonItr=Left(begin,end,index); }else{ return; } } } //STL风格 //逻辑上的heap大小减小1,但是容器的大小不变 template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::PopHeap(RandomItr begin,RandomItr end, CmpOpr cmp,SwapDo sd){ if(begin==end){ return; } --end; sd(*begin,*end); HeapDown(begin,end,begin,cmp,sd); } //入堆 template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::PushHeap(RandomItr begin,RandomItr end, CmpOpr cmp,SwapDo sd){ HeapUp(begin,end,--end,cmp,sd); } //制作堆 template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::MakeHeap(RandomItr begin,RandomItr end, CmpOpr cmp,SwapDo sd){ for(RandomItr itr=begin+(end-begin)/2-1;itr!=begin/*注意越界*/;--itr){ HeapDown(begin,end,itr,cmp,sd); } //当itr==begin时,--itr会越界,最后补加调整首个元素 HeapDown(begin,end,begin,cmp,sd); } //判断是否是堆 template<class RandomItr, class CmpOpr> bool MyHeap::IsHeap(RandomItr begin,RandomItr end,CmpOpr cmp){ for(RandomItr itr=begin+(end-begin)/2-1;itr!=begin/*注意越界*/;--itr){ if(cmp(*itr,*Left(begin,end,itr))){ return false; } if(Right(begin,end,itr)<end && cmp(*itr,*Right(begin,end,itr))){ return false; } } //当itr==begin时,--itr会越界,最后补加判断首个元素 if(cmp(*begin,*Left(begin,end,begin))){ return false; } if(Right(begin,end,begin)!=end && cmp(*begin,*Right(begin,end,begin))){ return false; } return true; } //堆排序 template<class RandomItr,class CmpOpr,class SwapDo> void MyHeap::SortHeap(RandomItr begin,RandomItr end, CmpOpr cmp,SwapDo sd){ //建堆 MakeHeap(begin,end,cmp,sd); //排序 for(RandomItr newEnd=end-1;newEnd!=begin/*注意越界*/;--newEnd){ sd(*newEnd,*begin); HeapDown(begin,newEnd,begin,cmp,sd); } } #endif 使用时,直接调用TestSTLHeap方法就可以了。 希望对大家有用~~~