本算法是对<算法导论>相关章节的实现:
下面贴代码:
#include<iostream>
#include<cstdlib>
using namespace std;
struct node
{
node(int d):data(d),degree(0),parent(NULL),child(NULL),sibling(NULL){}
int data;
int degree;
node* parent;
node* child;
node* sibling;
};
class BinomialHeap
{
public:
BinomialHeap():head(NULL){}
~BinomialHeap(){ClearHeap(head);};
node* Minimum();
void ExtractMin();
void Union(BinomialHeap*,BinomialHeap*);
void Insert(int);
node* GetHead();
void SetHead(node*);
bool Empty();
private:
node* head;
void UnionNode(node*,node*);
node* MergeBinomialHeap(BinomialHeap*,BinomialHeap*);
void ClearHeap(node*);
node* Reverse(node*);
};
node* BinomialHeap::Minimum()
{
node *nd=head,*min=head;
while(nd!=NULL)
{
if(nd->data<min->data)
min=nd;
nd=nd->sibling;
}
return min;
}
void BinomialHeap::ExtractMin()
{
if(head!=NULL)
{
node *nd=head,*n=head;
while(nd!=NULL)
{
if(nd->data<n->data)
n=nd;
nd=nd->sibling;
}
nd=head;
while(nd->sibling!=n&&nd->sibling!=NULL)
nd=nd->sibling;
nd->sibling=n->sibling;
BinomialHeap* tmpheap=new BinomialHeap();
nd=n->child;
while(nd!=NULL&&nd->sibling!=NULL)
nd=nd->sibling;
tmpheap->SetHead(nd);
Reverse(n->child);
if(n==head)
{
head=NULL;
}
delete n;
n=NULL;
Union(this,tmpheap);
}
}
void BinomialHeap::Union(BinomialHeap *h1,BinomialHeap *h2)
{
node* nd=MergeBinomialHeap(h1,h2);
if(nd==NULL)
{
head=NULL;
exit(0);
}
node* x=nd;
node* pre=NULL;
node* sib;
while(x!=NULL&&x->sibling!=NULL)
{
sib=x->sibling;
if((x->degree!=sib->degree)||(sib->sibling!=NULL&&x->degree==sib->sibling->degree))
{
pre=x;
x=x->sibling;
}
else
{
if(x->data<=sib->data)
{
x->sibling=sib->sibling;
UnionNode(sib,x);
}
else
{
if(pre==NULL)
{
nd=sib;
}
else
{
pre->sibling=sib;
}
UnionNode(x,sib);
x=sib;
}
}
if(x==NULL)
break;
}
head=nd;
}
void BinomialHeap::Insert(int data)
{
BinomialHeap* tmpHeap=new BinomialHeap();
node* nd=new node(data);
tmpHeap->SetHead(nd);
Union(this,tmpHeap);
}
node* BinomialHeap::GetHead()
{
return head;
}
void BinomialHeap::SetHead(node* nd)
{
head=nd;
}
bool BinomialHeap::Empty()
{
return head==NULL;
}
void BinomialHeap::UnionNode(node *nd1,node *nd2)
{
nd1->parent=nd2;
nd1->sibling=nd2->child;
nd2->child=nd1;
nd2->degree+=1;
}
node* BinomialHeap::Reverse(node* nd)
{
if(nd!=NULL)
{
if(nd->sibling!=NULL)
{
Reverse(nd->sibling)->sibling=nd;
}
nd->sibling=NULL;
return nd;
}
}
node* BinomialHeap::MergeBinomialHeap(BinomialHeap* h1,BinomialHeap* h2)
{
node *nd,*sib,*nd1,*nd2;
nd1=h1->GetHead();
nd2=h2->GetHead();
h1->SetHead(NULL);
h2->SetHead(NULL);
if(nd1==NULL||nd2==NULL)
{
nd=(nd1==NULL?nd2:nd1);
return nd;
}
if(nd1->degree<nd2->degree)
{
nd=nd1;
nd1=nd1->sibling;
}
else
{
nd=nd2;
nd2=nd2->sibling;
}
sib=nd;
while(nd1!=NULL&&nd2!=NULL)
{
if(nd1->degree<nd2->degree)
{
sib->sibling=nd1;
nd1=nd1->sibling;
}
else
{
sib->sibling=nd2;
nd2=nd2->sibling;
}
sib=sib->sibling;
}
if(nd1!=NULL)
{
sib->sibling=nd1;
}
if(nd2!=NULL)
{
sib->sibling=nd2;
}
return nd;
}
void BinomialHeap::ClearHeap(node* nd)
{
if(nd!=NULL)
{
ClearHeap(nd->sibling);
ClearHeap(nd->child);
delete nd;
nd=NULL;
}
}
本算法的核心就是Union(BinomialHeap*,BinomialHeap*)算法,而Union算法的核心就是一句话:
For any nonnegative interger k,there is at most one binomial tree in H whose root has degree k.
Union算法是怎么实现的呢?算法导论把Union的过程分成了四种情况:
1.degree[x]<degree[next-x]
2.degree[x]==degree[next-x]==degree[next[next-x]].
3.degree[x]=degree[next-x]&&key[x]<=key[next-x]
4.degree[x]=degree[next-x]&&key[x]>key[next-x]
第一种情况是很好理解的(要先理解MergeBinomialHeap的过程以及binomial heap的结构),因为degree[x]<degree[next-x]满足binomial heap的结构,所以直接pass
第三种和第四种情况也是很好理解的(先理解binomial tree的机理),两个高度相同的,直接合并就好了.
第二种情况有点问题,为什么会出现连续三个高度相同的binomial tree呢,在binomial heap中不是每棵树的高度都不一样吗.....k,k,.....这种情况是比较正常和好理解的.....k,k,k,....结构是怎么出来的呢?原因就是....k,k,k+1,k+1,....,在对前两个高度为k的binomial tree进行合并之后,就出现了,...k+1,k+1,k+1,....,为什么三个连续的要跳过第一个呢,因为对第一个合并之后得到...k+2,k+1,...违反了binomial heap的结构,所以不能合并.
所以,要先理解binomial tree的结构,后理解binomial heap的结构,接下来的就水到渠成,该怎么写就怎么写了.
=========发什么疯,害我重写一遍=========