#include <iostream>
#include <vector>
using namespace std;
class heap;
class node
{
//节点类型,每一个二项堆之中的节点都会包含的东西。
int key;//节点的关键字
int degree;//节点度数,包含子女的个数
node* p;//指向其父辈的指针
node* sibling;//指向该节点的最紧的右节点
node* child;//指向其最左边的孩子的指针。
public:
node(int rkey,int rdegree,node* rp,node* rsibling,node* rchild):key(rkey),degree(rdegree),p(rp),sibling(rsibling),child(rchild){}
//在构造一个节点的时候就已经把该节点的相应的信息确定了
friend void heapmin(heap* p);
friend void link(node* y,node* z);
friend node* merge(heap* h1,heap* h2);
friend node* heapunion(heap* h1,heap* h2);
friend void insert(heap *p,node* x);
friend void decreasekey(heap* p,node* x,int k);
};
class heap
{
//二项堆类型,包含的东西有指向堆首的一个指针以及很多的节点(n个)
node* head;//head指向的是一个节点,节点为堆首的元素
vector<node> nv;//包含有的是n个node类型的节点
public:
heap():head(NULL){}//仅仅是默认的构造这么一个堆的对象,带有实参的默认构造函数,对于那些没操作的元素是使用自己的默认构造函数赋值
//默认构造函数是把那些
friend node* merge(heap* h1,heap* h2);
friend node* heapunion(heap* h1,heap* h2);
friend void insert(heap *p,node* x);
friend void decreasekey(heap* p,node* x,int k);
friend void heapmin(heap* p);
};
// void heapcreat()//构造一个空的堆,实际上可以使用上面的默认构造函数来进行,可以是提供
// {
// //这里还是不要使用的了,用那个构造函数实现。
// }
void heapmin(heap* p)
{
node* y=NULL;//y用于
node* x=p->head;//这里赋值为head的话,那么要明确的就是在后面的步骤之中的话这个head的具体值是需要确定的
int min=0x7fffffff;
while (x!=NULL)
{
if(min>x->key)
{
min=x->key;
y=x;
}
x=x->sibling;
}
cout<<"最小的节点地址是:"<<y<<endl;
}
void link(node* y,node* z)//这里的y和z是需要是树的节点,这里的话在下面的操作之中是需要明确的
{
//这里是让z成为y的父节点
y->p=z;
y->sibling=z->child;
z->child=y;
z->degree=z->degree+1;
cout<<"link步骤完成"<<endl;
}//上面的操作只是把2个二项树的根节点进行结合
node* merge(heap* h1,heap* h2)//使用归并排序
{
heap* mp=new heap();
node *h = mp->head;
while(h1->head!=NULL&&h2->head!=NULL)
{
if(h1->head->degree>h2->head->degree)
{
if(mp->head == NULL)
{
mp->head = h2->head;
h = mp->head;
h->sibling = NULL;
h2->head = h2->head->sibling;
}
else
{
h->sibling = h2->head;
h = h->sibling;
h2->head = h2->head->sibling;
h->sibling = NULL;
}
/* mp->head=h2->head;
mp->head=mp->head->sibling;
h2->head=h2->head->sibling;*/
}
else
{
/* mp->head=h1->head;
mp->head=mp->head->sibling;
h1->head=h1->head->sibling;*/
if(mp->head == NULL)
{
mp->head = h1->head;
h = mp->head;
h1->head = h1->head->sibling;
h->sibling = NULL;
}
else
{
h->sibling = h1->head;
h = h->sibling;
h1->head = h1->head->sibling;
h->sibling = NULL;
}
}
}
// while (h1->head!=NULL)
if(h1->head != NULL)
{
if(mp->head == NULL)
mp->head = h1->head;
else
h->sibling = h1->head;
/* mp->head=h1->head;
mp->head=mp->head->sibling;
h1->head=h1->head->sibling;*/
}
// while (h2->head!=NULL)
if (h2->head!=NULL)
{
if(mp->head == NULL)
mp->head = h2->head;
else
h->sibling = h2->head;
/* mp->head=h2->head;
mp->head=mp->head->sibling;
h2->head=h2->head->sibling;*/
}
cout<<"归并完成"<<endl;
return mp->head;
}
node* heapunion(heap* h1,heap* h2)
{
heap* np=new heap();//构建一个新的堆,堆中含有的是一个指向该堆的堆首的指针,以及很多的的节点元素,这里是没有赋值的
np->head=merge(h1,h2);//把2个堆的根表用归并排序结合在一起,然后就是给了那个新建立的那个堆的指针。
if(np->head==NULL)
return np->head;
node* x=np->head;
node* prevx=NULL;
node* nextx=x->sibling;
while (nextx!=NULL)
{
if((x->degree!=nextx->degree)||(nextx->sibling!=NULL)&&(x->degree==nextx->degree==nextx->sibling->degree))
{//2种情况下的会相应的调用这个步骤,一个就是连续2个表中的数据度数不一样,还有就是连续三个数的度数一样的,那么就会相应的如下
prevx=x;
x=nextx;
}
else if(x->key<=nextx->key)//如果不是上面的2中情况的话就相应的调用下面的这个步骤,也就是我们的两个二项树的根的link
{
x->sibling=nextx->sibling;
link(nextx,x);//由于对于每一个二项堆的每一个二项树而言的话都是一个最小堆的性质,那么对于2个二项树合并的话,必定是键值小的在上面
}
else
{
if(prevx==NULL)//如果x前面一个节点是一个空的话,那么由于我们的next-x需要去链接该节点,相应的处理
np->head=nextx;//中间把x点拿到next-x下的话就要如此的做下去
else
np->head->sibling=nextx;
link(x,nextx);
x=nextx;//完成了
}
nextx=x->sibling;//next-x为新节点的下一个,向前推进
}
return np->head;//对于那些根表进行了操作之后得到的新的根表。
}
void insert(heap *p,node* x)
{
heap* np=new heap();//构建一个新的堆,空的。使用的就是2个堆进行合并的想法,堆中的节点都是空
x->p=NULL;
x->child=NULL;
x->key=0;
x->sibling=NULL;
x->degree=0;
np->head=x;
p->head=heapunion(p,np);
cout<<"完成插入节点,完结后的堆的首地址:"<<p<<endl;
}
void decreasekey(heap* p,node* x,int k)
{
if(k>x->key)
{
cerr<<"error"<<endl;
return ;
}
x->key=k;
node* y=x;
node* z=y->p;
while (z!=NULL&&z->key>y->key)
{
swap(z->key,y->key);//交换键值,之后就是向上追溯
y=z;
z=y->p;//上面是向上追溯,直到z为null,成为最小堆性质。
}
}
int main()
{
heap *rp=new heap();//建立一个空的堆,堆中的各个节点的数是空的。
node *rn1=new node(4,0,NULL,NULL,NULL);
node *rn2=new node(5,0,NULL,NULL,NULL);
//插入一把
insert(rp,rn1);
insert(rp,rn2);
/*link(rn1,rn2);*/
decreasekey(rp,rn2,7);
return 0;
}
趁师兄,师姐们还在,偶要多学,多问啊。嘿嘿
二项堆
最新推荐文章于 2025-04-22 10:03:52 发布