平衡树
简介:
平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。
Treap:
简介:
Treap代码实现相对简单的一个算法,Treap是 heap+Tree,既满足堆的性质也满足平衡树的性质,一棵树的节点上有一个data用于存数据,fix是一个堆的优先级(假设我们是小顶堆),key是平衡树的比较值;key一般是给出的,然而fix我们随机生成,这样的随机会使得平衡树比较平衡。假设一棵排序二叉树插入一组有序的数,就会使得树退化为一条链。我们在插入的时候为每个节点随机生成一个fix(优先级)。插入时满足排序二叉树的性质。插入完成时检查是否满足堆的性质,并进行旋转操作使他满足堆的性质。
旋转操作:
为了满足堆的性质,我们需要对这棵树进行旋转以达到堆的性质。旋转操作看图
如图是旋转操作,我用的是指针链式的写法:所以,每次旋转需要调整两个节点的父子关系。以及指向P或者Q的那个指针。
下面给出指针的写法
void rotate(Node* &o,int d) { Node *k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o=k; }上面是旋转操作,d传0代表左旋,d为1代表右旋;
当我们了解旋转操作后,接下来;
插入元素操作:
首先根据排序二叉树的性质找到叶子节点,将新的元素插入到叶子节点。当插入之后会破坏堆的性质,然后进行旋转操作让他满足堆的性质,因为那样旋转不会破坏排序二叉树的性质的。所以旋转只需要考虑堆的性质。
删除操作:
用排序二叉树的性质去找要删除的元素位置,找到之后判断是否左右都是有儿子,如果不是直接删除,把指向他的指针,直接指向他的儿子节点。如果是就需要通过旋转操作。把需要删除的元素往下旋转。旋转时为了满足堆的性质(如果是小顶堆)需要比较左右儿子的大小,将该元素与小值的儿子进行旋转。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 using namespace std; 5 int sz; 6 const int maxn=1e6+10; 7 struct Node 8 { 9 Node *ch[2]; 10 int r,v,info;//v是顾客优先级,info是顾客的编号,r由rand()生成 11 int cmp(int x) 12 { 13 if(x==v) return -1; 14 return x<v? 0:1; 15 } 16 }T[maxn]; 17 Node * newnode(int _v,int _info) 18 { 19 Node *res=&T[sz]; 20 T[sz].v=_v,T[sz].info=_info; 21 T[sz].r=rand(); 22 T[sz].ch[0]=T[sz].ch[1]=NULL; 23 sz++; 24 return res; 25 } 26 void rotate(Node* &o,int d) 27 { 28 Node *k=o->ch[d^1]; 29 o->ch[d^1]=k->ch[d]; 30 k->ch[d]=o; 31 o=k; 32 } 33 void insert(Node* &o,int v,int info) 34 { 35 if(o==NULL) o=newnode(v,info); 36 else 37 { 38 int d= v < o->v?0:1; 39 insert(o->ch[d],v,info); 40 if(o->ch[d]->r > o->r) 41 rotate(o,d^1); 42 } 43 } 44 void remove(Node *&o,int v) 45 { 46 int d=o->cmp(v); 47 if(d==-1) 48 { 49 if(o->ch[0] && o->ch[1]) 50 { 51 int d2 = o->ch[0]->r < o->ch[1]->r ?0:1; 52 rotate(o,d2); 53 remove(o->ch[d2],v); 54 } 55 else 56 { 57 if(o->ch[0]==NULL)o=o->ch[1]; 58 else o=o->ch[0]; 59 } 60 } 61 else remove(o->ch[d],v); 62 } 63 int find_max(Node *o)//找到最大v值 64 { 65 if(o->ch[1]==NULL) 66 { 67 printf("%d ",o->info); 68 return o->v; 69 } 70 return find_max(o->ch[1]); 71 } 72 int find_min(Node *o)//找到最小v值 73 { 74 if(o->ch[0]==NULL) 75 { 76 printf("%d ",o->info); 77 return o->v; 78 } 79 return find_min(o->ch[0]); 80 } 81 int main() 82 { 83 int op; 84 Node *root=NULL; 85 sz=0; 86 while(scanf("%d",&op)==1&&op) 87 { 88 if(op==1) 89 { 90 int info,v; 91 scanf("%d%d",&info,&v); 92 insert(root,v,info); 93 } 94 else if(op==2) 95 { 96 if(root==NULL) 97 { 98 printf("0 "); 99 continue; 100 } 101 int v=find_max(root); 102 remove(root,v); 103 } 104 else if(op==3) 105 { 106 if(root==NULL) 107 { 108 printf("0 "); 109 continue; 110 } 111 int v=find_min(root); 112 remove(root,v); 113 } 114 } 115 return 0; 116 }
优先队列的实现。