配对堆是一种可并堆(可以将两个堆合并,且速度快),时间复杂度:
合并merge:O(1) 插入push:O(1) 弹出pop:O(logn)
配对堆不是二叉堆(我一开始不知道这个所以一直搞不懂)
配对堆存树的方式不一样,如图,对于每个节点,有一条边指向最左边的儿子,一条指向他右边的兄弟
和普通树的对比:(灵魂画图)(蓝色为普通方式,红色为做兄弟右儿子)
以下均以大根堆为例
合并:
很简单,比较两树树根,将小的的根作为大的左儿子,然后将小的的根的右兄弟指为大的原来的左儿子
如图:(根的值在点上)
插入:
直接将插入的点作为一个堆,然后和原堆合并
弹出:
把根断开
从左到右依次两两合并,再从左到右依次合并,具体细节可参考代码
代码:
#include<cstdio> inline void swap(int &x,int &y){ x^=y^=x^=y; } //大根堆 struct pairing_heap{ struct node{ int v,s,r; }tree[10010]; int tot,root; pairing_heap(int _tot=0,int _root=0):tot(_tot),root(_root){} int Merge(int x,int y){//合并根为x,y的两棵树,返回根 if(!x||!y){root=x+y;return x+y;}//有一个是空树(为0) if(tree[x].v<tree[y].v)swap(x,y); tree[y].r=tree[x].s;tree[x].s=y; return root=x; } int Push(int x){ tree[++tot].v=x; tree[tot].r=tree[tot].s=0; return Merge(root,tot); } void Del(int x){ tree[root].s=tree[x].r;tree[x].r=0; } int Pop(){ int x=tree[root].s,y=tree[x].r; if(x==0)return 0; Del(x);if(y)Del(y); return root=Merge(Merge(x,y),Pop()); } int Top(){ return tree[root].v; } }; int main(){ pairing_heap q; printf("input “0”for push,“1” for top,“2” for pop or “-1” for exit "); while(1){ int ques; scanf("%d",&ques); if(ques==0){ int x; scanf("%d",&x); q.Push(x); }else if(ques==1){ printf("%d ",q.Top()); }else if(ques==2){ q.Pop(); }else if(ques==-1){ break; } } return 0; }