本算法是对<算法导论>相关章节伪代码的实现:
先贴代码:
#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;
class FibonacciHeap;
class node{
friend class FibonacciHeap;
node(int v):key(v),height(0),parent(NULL),left(this),right(this),child(NULL),mark(false){}
int key;
int height;
node* parent;
node* left;
node* right;
node* child;
bool mark;
};
class FibonacciHeap
{
friend ostream& operator<<(ostream&,node*);
public:
FibonacciHeap():min(NULL),total(0){};
~FibonacciHeap();
node* minimum();
void extractMin();
void insert(int);
void deleteNode(node*);
void decreaseNode(node*,int);
bool empty();
private:
node* min;
node* arr[1000000];
int total;
void removeChild(node*);
void consolidate();
void cut(node*);
void cascadingCut(node*);
FibonacciHeap* unionHeap(FibonacciHeap*,FibonacciHeap*);
void linkNode(node*,node*);
};
FibonacciHeap::~FibonacciHeap()
{
while(min)
{
extractMin();
}
for(int i=0;i<1000000;++i)
{
delete arr[i];
arr[i]=NULL;
}
}
node* FibonacciHeap::minimum()
{
return min;
}
void FibonacciHeap::extractMin()
{
if(min==NULL)
exit(0);
node *tmp=NULL,*tmpmin=NULL;
while(min->child!=NULL)
{
removeChild(min->child);
}
if(min->right==min)
{
delete min;
min=NULL;
}
else
{
tmpmin=min;
min=NULL;
tmp=tmpmin->right;
while(tmp!=tmpmin)
{
if(min==NULL||tmp->key<min->key)
min=tmp;
tmp=tmp->right;
}
tmpmin->right->left=tmpmin->left;
tmpmin->left->right=tmpmin->right;
delete tmpmin;
tmpmin=NULL;
tmp=NULL;
}
if(--total>0)
consolidate();
}
void FibonacciHeap::insert(int data)
{
node* nd=new node(data);
nd->left=nd;
nd->right=nd;
FibonacciHeap* addheap=new FibonacciHeap();
addheap->min=nd;
addheap->total=1;
addheap=unionHeap(this,addheap);
this->min=addheap->min;
this->total=addheap->total;
addheap=NULL;
}
void FibonacciHeap::deleteNode(node* nd)
{
nd->key=-32767;
extractMin();
}
void FibonacciHeap::decreaseNode(node* nd,int data)
{
nd->key=data;
node* p=nd->parent;
if(p!=NULL&&nd->key<p->key)
{
cut(nd);
cascadingCut(p);
}
if(nd->key<min->key)
{
min=nd;
}
}
void FibonacciHeap::removeChild(node* nd)
{
if(nd->right==nd)
{
nd->parent->child=NULL;
}
else
{
nd->right->left=nd->left;
nd->left->right=nd->right;
if(nd==nd->parent->child)
nd->parent->child=nd->right;
}
nd->right=nd->parent->right;
nd->parent->right->left=nd;
nd->left=nd->parent;
nd->parent->right=nd;
nd->parent=NULL;
nd->mark=false;
}
void FibonacciHeap::consolidate()
{
node *nd,*tmp;
int height;
for(int i=0;i<total;++i)
arr[i]=NULL;
arr[min->height]=min;
nd=min->right;
while(nd!=min)
{
tmp=nd;
height=tmp->height;
while(arr[height]!=NULL&&arr[height]!=nd)
{
if(arr[height]->key<tmp->key)
swap(arr[height],tmp);
linkNode(tmp,arr[height]);
arr[height]=NULL;
height=tmp->height;
}
arr[height]=tmp;
nd=tmp->right;
}
}
void FibonacciHeap::cut(node *curnode)
{
removeChild(curnode);
curnode->mark=false;
}
void FibonacciHeap::cascadingCut(node *pnode)
{
node* p=pnode->parent;
if(p!=NULL)
{
if(pnode->mark==false)
pnode->mark=true;
else
{
cut(pnode);
cascadingCut(p);
}
}
}
FibonacciHeap* FibonacciHeap::unionHeap(FibonacciHeap* hp1,FibonacciHeap* hp2)
{
FibonacciHeap* newHeap=new FibonacciHeap();
newHeap->min=(hp1->min!=NULL)?hp1->min:hp2->min;
if(newHeap->min!=hp2->min)
{
newHeap->min->right->left=hp2->min->left;
hp2->min->left->right=newHeap->min->right;
hp2->min->left=newHeap->min;
newHeap->min->right=hp2->min;
if(hp2->min->key<newHeap->min->key)
newHeap->min=hp2->min;
}
newHeap->total=hp1->total+hp2->total;
hp1->min=NULL;
hp2->min=NULL;
return newHeap;
}
void FibonacciHeap::linkNode(node *tarNode,node *obNode)
{
obNode->left->right=obNode->right;
obNode->right->left=obNode->left;
if(tarNode->child!=NULL)
{
obNode->left=tarNode->child->left;
tarNode->child->left->right=obNode;
obNode->right=tarNode->child;
tarNode->child->left=obNode;
}
else
{
obNode->left=obNode;
obNode->right=obNode;
}
obNode->parent=tarNode;
tarNode->child=obNode;
++tarNode->height;
}
bool FibonacciHeap::empty()
{
return min==NULL;
}
算法导论上讲的很明白了.
比较FibonacciHeap和BinomialHeap,为什么FibonacciHeap不在插入的时候对根节点进行合并呢?因为FibonacciHeap是最小有限数列,它的最主要功能是void minimum()和void extractMin(),其他功能都是附属功能,既然(node*)min已经指向的最小节点,所以就没有必要在insert的时候合并以保持FibonacciHeap的结构特点了.况且在定义中我们可以看出FibonacciHeap对结构的要求不想BinomialHeap那么高,所以从定义上讲也没有必要合并.更重要的是,在extractMin()操作的时候还会剪枝,如果在插入的时候就进行合并的话,反而在extractMin的时候还会加上removeChild(node*)和consolidate()的操作,多此一举了.所以,FibonacciHeap和binomialHeap的最大不同之处是FibonacciHeap放弃了结构上的一致性,以换取更快的处理速度.这一点在进行decrease(node*,int)的时候特别明显.
在进行decrease(node*,int)的时候为什么要进行cut(node*)和cascadingCut(node*)呢?出于结构一致性的考量,应该进行如下操作:
node* pnode=nd->parent;
while(pnode->key>key)
{
swap(nd->key,pnode->key);
nd=pnode;
pnode=nd->parent;
}
才对,为什么要剪枝呢?因为FibonacciHeap最主要的功能是minimum()和extractMin(),反正在进行extractMin()的时候还要剪枝,往上遍历了后来还要减去,出于速度上的考量,干脆一开始就把它减去.而且往上遍历不知道要遍历多少个,直接把剪去更加省事.
FibonacciHeap性能上有多强劲现在我还感受不出来,因为没有那么多数据...现在感觉比BinomialHeap也快不了多少...