正文

FibonacciHeap的C++模板实现2006-11-23 17:01:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/rickone/20674.html

分享到:

FibonacciHeap是一种优先队列,它的性能如下图所示。 就平均而言有很好的性能,所以在一些图论算法中可以用来作改进算法的数据结构,尤其是那些稀疏图,总之是很好的工具。下面以设计者的角度简单描述我设计它的过程和思路。 1、组织方法采用C++提供的模板支持设计这个模板类,以达到很高的适应性。参数列表中只有一个类class T,它表示这个容器的元素类型,然后需要对它进行小的封装,封装的结果是得到一个内部小数据结构fibnode,如上图所示。 fibnode是组织FibonacciTree的结点结构,它包括了全部的指针和标记,整个FibonacciHeap就由它组成的,这个FibonacciTree在外部看来,只有一个min指针,指向它的根一层结点。 由于这样的组织形式,所以在析构的时候需要以递归的方式进行,递归的调用release()完成内存单元的回收。 这样的组织元素会遇到一个外部的问题,那就是内外数据的映射,由于元素是采用COPY的方式放入容器的,所以在内部是不知道哪个元素被封在哪个fibnode里,在内部确定一个元素的唯一方法就是找到它的fibnode指针,而为此如果做查找运算的话那它的优势将无法发挥出来。这个问题我没有在内部给出解决方法,原因是为了高适应性,因为这个T是未知的,所以我没办法给个O(1)的映射算法,如果用红黑树做Map,那会有O(lbn)的时间开销,那将使Decrease_Key()等调用的性能下降,唯一更好的办法是采用Hash表,而如果确定Hash函数又是和T有关的事情,所以这些事留给使用着在外部解决,根据具体的数据内容选择好的Hash函数,做外部的从T到const fibnode*的映射。值得说明的是,任何的fibnode指针都会在insert()过程的返回值中得到,如列程序所示: Heap::FibonacciHeap<int> h;const Heap::FibonacciHeap<int>::fibnode *x;x=h.insert(100); x将得到元素100的内部指针。于是可以将x作为Decrease_Key()的参数进行操作。 2、几个实现中的问题从FibonacciHeap的算法描述到实现其实不是太难,很多操作都轻而易举的事,我额外定义的内部过程有: remove(x)dblist_union(x,y) 分别表示从双端链表中删除一个元素,和合并两个双端链表,双端链表可以看成是环,对孩子的遍历或对兄弟的遍历都会变得非常容易实现,这是整个算法成功的关键。 刚才在写consolidate()过程时遇到逻辑错误,问题出在w跑整个root list的时候,在标记结果标志上是用的判断‘while(w!=min)’,而在这个过程中,min有可能被改变,去作为其它结点的孩子,所以出现错误。 还有一个问题就是在kill()过程(即算法描述中的delete(),为了和C++关键字区分开)需要定义一个负无穷大,而T的外部特性又不清楚,怎么办?我设了一个默认参数,标记是否是负无穷大,只要在进行比较的语句处多加一个判断即可,比较巧妙的避开了负无穷大的元素。 3、实现源码和说明本程序是自由代码可自由使用,其实是我的作业,没有兼容STL中的容器标准,STL中有PriorityQueue的标准容器,程序中也可能存在尚未发现的BUG,如果发现请告诉我。 由于是用的模板类,所以两个实现部分我也用了.h文件,如果用.cpp分有连接错误,当时我不知为什么,其实原因很简单,模板是采用所谓的晚连编,是在具体的class T定义的地方进行确定代码的,所以那些cpp不会被先编译,所以会出现连接错误。代码和BinaryHeap组织在一起,同在Heap的namespace下面。全部代码如下: //:priorityqueue.h文件,外部参数说明#include <vector>#ifndef HEAP_DEF_RICKONE_20061123#define HEAP_DEF_RICKONE_20061123namespace Heap{ //Binary Heap template <class T> class BinaryHeap {  std::vector<T> h;  int n; public:  BinaryHeap();  void max_heapify(int i);  void min_heapify(int i);  void insert(const T &e);  T minnum() const;  T extract_min();  void decrease_key(int x,const T &k);  void kill(int x); };  //Fibonacci Heap template <class T> class FibonacciHeap {  enum{NEGATIVE_INFINITY=1985};  struct fibnode  {   T data;   fibnode *p,*child,*left,*right;   int degree;   bool mark;  } *min;  unsigned long int n; public:  FibonacciHeap();//Construct a Heap  ~FibonacciHeap();  const fibnode* insert(const T &e);  T minnum() const;  T extract_min();  void decrease_key(const fibnode *x,const T &k,int TAG=0);  void kill(const fibnode *x);  void heap_union(FibonacciHeap<T> &h);  //for test  void Display();  void Print(int depth,fibnode *x); private:  void release(fibnode *x);  void remove(fibnode *x);  void dblist_union(fibnode *a,fibnode *b);  void consolidate();  void cut(fibnode *x,fibnode *y);  void cascading_cut(fibnode *y); };}#endif //:binaryheap.h BinaryHeap实现#include "priorityqueue.h" template <class T>Heap::BinaryHeap<T>::BinaryHeap(){ h.push_back(T()); n=1;} template <class T>void Heap::BinaryHeap<T>::max_heapify(int i){ //float up for(;i>1;) {  int p=i/2;  if(h[i]<h[p])  {   T temp(h[i]);   h[i]=h[p];   h[p]=temp;   i=p;  }  else   break; }} template <class T>void Heap::BinaryHeap<T>::min_heapify(int i){ //float down if(i<1 || i>=n)  return; for(;;) {  int left=i*2;  int right=left+1;  int smallest;  if(left>=n)   break;  if(right>=n)   smallest=left;  else  {   if(h[left]<h[right])    smallest=left;   else    smallest=right;  }  if(h[smallest]<h[i])  {   T temp(h[i]);   h[i]=h[smallest];   h[smallest]=temp;   i=smallest;  }  else   break; }} template <class T>void Heap::BinaryHeap<T>::insert(const T &e){ if(n>=h.size())  h.push_back(e); else  h[n]=e; n++; max_heapify(n-1);} template <class T>T Heap::BinaryHeap<T>::minnum() const{ if(n>1)  return h[1]; return T();} template <class T>void Heap::BinaryHeap<T>::decrease_key(int x,const T &k){ if(h[x]<k) {  //error warning  return; } h[x]=k; max_heapify(x);} template <class T>void Heap::BinaryHeap<T>::kill(int x){ if(x>=1 && x<n) {  h[x]=h[n-1];  min_heapify(x);  n--; }} template <class T>T Heap::BinaryHeap<T>::extract_min(){ if(n>1) {  T min=h[1];  kill(1);  return min; } return h[0];} //:fibonacciheap.h FibonacciHeap实现//中间包括一些原用于测试的代码,可去掉#include "priorityqueue.h" template <class T>Heap::FibonacciHeap<T>::FibonacciHeap(){ min=NULL; n=0;} template <class T>void Heap::FibonacciHeap<T>::release(fibnode *x){ if(x==NULL)  return; fibnode *p=x,*q; do {  q=p;  p=p->right;  release(q->child); } while(p!=x); do {  q=p;  p=p->right;  //printf("deleting %d ...\n",q->data);  delete q; } while(p!=x);} template <class T>Heap::FibonacciHeap<T>::~FibonacciHeap(){ release(min);} template <class T>void Heap::FibonacciHeap<T>::remove(fibnode *x){ if(x==NULL)  return; fibnode *l,*r; l=x->left; r=x->right; l->right=r; r->left=l; x->left=x; x->right=x;} template <class T>void Heap::FibonacciHeap<T>::dblist_union(fibnode *a,fibnode *b){ if(a==NULL || b==NULL)  return; fibnode *al=a->left,*bl=b->left; al->right=b; a->left=bl; bl->right=a; b->left=al;} template <class T>const Heap::FibonacciHeap<T>::fibnode* Heap::FibonacciHeap<T>::insert(const T &e){ fibnode *x=new fibnode; x->degree=0; x->p=NULL; x->child=NULL; x->left=x; x->right=x; x->mark=false; x->data=e; if(min==NULL)  min=x; else  dblist_union(min,x); if(e<min->data)  min=x; ++n; return (const fibnode*)x;} template <class T>T Heap::FibonacciHeap<T>::minnum() const{ if(min==NULL)  return T(); return min->data;} template <class T>void Heap::FibonacciHeap<T>::heap_union(FibonacciHeap<T> &h){ dblist_union(min,h.min); if(min==NULL || (h.min !=NULL && h.min->data < min->data))  min=h.min; n+=h.n; h.min=NULL;} template <class T>void Heap::FibonacciHeap<T>::consolidate(){ fibnode *A[32]={NULL}; fibnode *w=min; do {  fibnode *x=w;  w=w->right;  int d=x->degree;  while(A[d]!=NULL)  {   fibnode *y=A[d];   if(y->data < x->data)   {    fibnode *tmp=x;    x=y;    y=tmp;   }   //   if(y==min)   {    if(w==min)     w=min->right;    min=min->right;   }   remove(y);   if(x->child==NULL)    x->child=y;   else    dblist_union(x->child,y);   y->p=x;   x->degree++;   y->mark=false;   A[d]=NULL;   d++;  }  A[d]=x; } while(w!=min); for(int i=0;i<32;++i) {  if(A[i]!=NULL)  {   if(A[i]->data < min->data)    min=A[i];  } }} template <class T>T Heap::FibonacciHeap<T>::extract_min(){ if(min==NULL)  return T(); T z=min->data; fibnode *x=min->child; if(x!=NULL) {  while(x->right!=min->child)  {   x->p=NULL;   x=x->right;  }  x->p=NULL; } //add each child of z to the root list dblist_union(min,min->child); //remove z from the root list fibnode *r=min->right; remove(min); // if(r==min) {  delete min;  min=NULL; } else {  delete min;  min=r;  consolidate(); } --n; return z;} template <class T>void Heap::FibonacciHeap<T>::cut(fibnode *x,fibnode *y){ if(y->child==x) {  if(x->right==x)   y->child=NULL;  else   y->child=x->right; } remove(x); y->degree--; dblist_union(min,x); x->p=NULL; x->mark=false;} template <class T>void Heap::FibonacciHeap<T>::cascading_cut(fibnode *y){ fibnode *z=y->p; if(z!=NULL) {  if(y->mark==false)   y->mark=true;  else  {   cut(y,z);   cascading_cut(z);  } }} template <class T>void Heap::FibonacciHeap<T>::decrease_key(const fibnode *cx,const T &k,int TAG){ fibnode *x=(fibnode*)cx,*y=x->p; if(x->data < k)  return;//error "new key is greater than current key x" x->data=k; if(y!=NULL && (TAG==NEGATIVE_INFINITY || (x->data < y->data))) {  cut(x,y);  cascading_cut(y); } if(TAG==NEGATIVE_INFINITY || x->data < min->data)  min=x;} template <class T>void Heap::FibonacciHeap<T>::kill(const fibnode *cx){ decrease_key(cx,T(),NEGATIVE_INFINITY); extract_min();} //------------------------------FOR TEST----------------------------template <class T>void Heap::FibonacciHeap<T>::Display(){ Print(0,min);} template <class T>void Heap::FibonacciHeap<T>::Print(int depth,fibnode *x){ int i; if(x==NULL) {  for(i=0;i<depth;++i)   printf(" ");  printf("-\n");  return; } fibnode *p=x,*q; do {  q=p;  p=p->right;  for(i=0;i<depth;++i)   printf(" ");  printf("<%d> degree=%d\n",q->data,q->degree);  Print(depth+1,q->child); } while(p!=x);} //:test.cpp 测试与使用#include "binaryheap.h"#include "fibonacciheap.h" int main(void){ Heap::FibonacciHeap<int> h; const Heap::FibonacciHeap<int>::fibnode *x; int a[]={3,7,1,2,3,12,5,4,-23,-4,0,2,-54},t=1; int b[]={43,-23,12}; int i,n=sizeof(a)/sizeof(int); x=h.insert(a[0]); for(i=1;i<n;++i)  h.insert(a[i]); h.extract_min(); h.Display(); printf("-=-=-=-=-=-=-=-\n"); h.kill(x); h.Display(); printf("-=-=-=-=-=-=-=-\n"); printf("extract_min=%d\n",h.extract_min()); return 0;} rickone 2006/11/23

阅读(15008) | 评论(4)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册