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_20061123
namespace 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
评论