STL风格的堆,有个问题,希望大家帮忙看看

bourneli-123 2010-05-20 09:01:11
代码如下


#include <stdexcept>
#include <iostream>
#include <vector>
using namespace std;
namespace MyHeap{

/****************************STL风格****************************/

//默认比较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);}
};

template<class RandomItr>
inline RandomItr Parent(RandomItr begin,RandomItr index){
return begin+(index-begin-1)/2;
}
template<class RandomItr>
inline RandomItr Left(RandomItr begin,RandomItr index){
return begin+(index-begin)*2+1;
}
template<class RandomItr>
inline RandomItr Right(RandomItr begin,RandomItr index){
return begin+(index-begin)*2+2;
}

//堆上浮
template<class RandomItr,
class CmpOpr,
class SwapDo>
void HeapUp(RandomItr begin,RandomItr end,
RandomItr index,
CmpOpr cmp=DefaultCmpOpr(),SwapDo sd=DefaultSwapDo());

//堆下沉
template<class RandomItr,
class CmpOpr,
class SwapDo>
void HeapDown(RandomItr begin,RandomItr end,
RandomItr index,
CmpOpr cmp=DefaultCmpOpr(),SwapDo sd=DefaultSwapDo());
//出堆
template<class RandomItr,
class CmpOpr,
class SwapDo>
void PopHeap(RandomItr begin,RandomItr end,
CmpOpr cmp=DefaultCmpOpr(),SwapDo sd=DefaultSwapDo());
//入堆
template<class HeapNode,
class RandomItr,
class CmpOpr,
class SwapDo>
void PushHeap(RandomItr begin,RandomItr end,
const HeapNode& newNode,
CmpOpr cmp=DefaultCmpOpr(),SwapDo sd=DefaultSwapDo());

//制作堆
template<class RandomItr,
class CmpOpr,
class SwapDo>
void MakeHeap(RandomItr begin,RandomItr end,
CmpOpr cmp=DefaultCmpOpr(),SwapDo sd=DefaultSwapDo());
//判断是否是堆
template<class RandomItr,
class CmpOpr>
bool IsHeap(RandomItr begin,RandomItr end,CmpOpr cmp=DefaultCmpOpr());

//堆排序
template<class RandomItr,
class CmpOpr,
class SwapDo>
void SortHeap(RandomItr begin,RandomItr end,
CmpOpr cmp,SwapDo sd);


/******************************以下为使用Demo******************************/
void TestSTLHeap(){
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);
}
SortHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>());

cout<<"Sorted "<<endl;
for(int i=0;i<N;++i){
cout<<heap[i]<<" "<<endl;
}
}

}


/****************************************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,index);
while(parItr>=begin && cmp(*index,*parItr)){
sd(*index,*parItr);
index=parItr;
parIdx=Parent(begin,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,index);
while(sonItr<end){
//找到最大儿子
if(sonItr+1<end && cmp(*(sonItr+1),*sonItr)){
++sonItr;
}
if(cmp(*sonItr,*index)){
sd(*sonItr,*index);//do after swapping
//继续向下寻找
index=sonItr;
sonItr=Left(begin,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);//do after swapping
HeapDown(begin,end,begin,cmp,sd);//stl 风格
}

//容器的真实大小必须大于逻辑大小
//入堆
template<class HeapNode,
class RandomItr,
class CmpOpr,
class SwapDo>
void MyHeap::PushHeap(RandomItr begin,RandomItr end,
const HeapNode& newNode,
CmpOpr cmp,SwapDo sd){
*end=newNode;
++end;
HeapUp(begin,end,end-1,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);
}
}

//判断是否是堆
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,itr))){
return false;
}
if(Right(begin,itr)<end && cmp(*itr,*Right(begin,itr))){
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+1;--newEnd){
sd(*newEnd,*begin);
HeapDown(begin,newEnd,begin,cmp,sd);
}
}



void main(){
MyHeap::TestSTLHeap();
system("pause");
}


编译可以通过,但是运行时就有错误,问题出现在模板的迭代器没有按照预期的方式工作。
...全文
77 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
bourneli-123 2010-05-21
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cheeralen 的回复:]
for(RandomItr itr=begin+(end-begin)/2-1;itr>=begin;--itr){
改成
for(RandomItr itr=begin+(end-begin)/2-1;itr!=begin;--itr){
[/Quote]
对我很有用,分给你了。
我修改过的版本如下:
http://blog.csdn.net/Taylor05/archive/2010/05/21/5614288.aspx
enjoy it~~~
bourneli-123 2010-05-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 cheeralen 的回复:]
因为heapdown函数里没有考虑begin==end的情况
[/Quote]
对我很有用,分给你了。
我修改过的版本如下:
http://blog.csdn.net/Taylor05/archive/2010/05/21/5614288.aspx
enjoy it~~~
pengzhixi 2010-05-20
  • 打赏
  • 举报
回复

#include <stdexcept>
#include <iostream>
#include <vector>
using namespace std;
namespace MyHeap{

/****************************STL风格****************************/

//默认比较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);}
};

template<class RandomItr>
inline RandomItr Parent(RandomItr begin,RandomItr index){
return begin+(index-begin-1)/2;
}
template<class RandomItr>
inline RandomItr Left(RandomItr begin,RandomItr index){
return begin+(index-begin)*2+1;
}
template<class RandomItr>
inline RandomItr Right(RandomItr begin,RandomItr index){
return begin+(index-begin)*2+2;
}

//堆上浮
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);
//出堆
template<class RandomItr,
class CmpOpr,
class SwapDo>
void PopHeap(RandomItr begin,RandomItr end,
CmpOpr cmp,SwapDo sd);
//入堆
template<class HeapNode,
class RandomItr,
class CmpOpr,
class SwapDo>
void PushHeap(RandomItr begin,RandomItr end,
const HeapNode& newNode,
CmpOpr cmp,SwapDo sd);

//制作堆
template<class RandomItr,
class CmpOpr,
class SwapDo>
void MakeHeap(RandomItr begin,RandomItr end,
CmpOpr,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 TestSTLHeap(){
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);
}
SortHeap(heap.begin(),heap.end(),DefaultCmpOpr<int>(),DefaultSwapDo<int>());

cout<<"Sorted "<<endl;
for(int i=0;i<N;++i){
cout<<heap[i]<<" "<<endl;
}
}

}


/****************************************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,index);
while(parItr>=begin && cmp(*index,*parItr)){
sd(*index,*parItr);
index=parItr;
parItr=Parent(begin,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,index);
while(sonItr<end){
//找到最大儿子
if(sonItr+1<end && cmp(*(sonItr+1),*sonItr)){
++sonItr;
}
if(cmp(*sonItr,*index)){
sd(*sonItr,*index);//do after swapping
//继续向下寻找
index=sonItr;
sonItr=Left(begin,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);//do after swapping
HeapDown(begin,end,begin,cmp,sd);//stl 风格
}

//容器的真实大小必须大于逻辑大小
//入堆
template<class HeapNode,
class RandomItr,
class CmpOpr,
class SwapDo>
void MyHeap::PushHeap(RandomItr begin,RandomItr end,
const HeapNode& newNode,
CmpOpr cmp,SwapDo sd){
*end=newNode;
++end;
HeapUp(begin,end,end-1,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);
}
}

//判断是否是堆
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,itr))){
return false;
}
if(Right(begin,itr)<end && cmp(*itr,*Right(begin,itr))){
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+1;--newEnd){
sd(*newEnd,*begin);
HeapDown(begin,newEnd,begin,cmp,sd);
}
}

int main(){
MyHeap::TestSTLHeap();

system("pause");
return 0;
}


DEV-C++下能编译运行,其他编译器没试过。
暗黑帝国 2010-05-20
  • 打赏
  • 举报
回复
因为heapdown函数里没有考虑begin==end的情况
chenyu2202863 2010-05-20
  • 打赏
  • 举报
回复
那你看看STL里HeapXXX相关的算法
暗黑帝国 2010-05-20
  • 打赏
  • 举报
回复
for(RandomItr itr=begin+(end-begin)/2-1;itr>=begin;--itr){
改成
for(RandomItr itr=begin+(end-begin)/2-1;itr!=begin;--itr){
bourneli-123 2010-05-20
  • 打赏
  • 举报
回复
sfsf

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧