Book--Treap小结

2015-03-16 20:13:07

总结:

  初学Treap,来小结一下。(部分摘自上交红书:算法与实现)

  struct Treap{

    int root , tcnt; //tcnt 为treap结点数

    int key[] , pro[] , son[][2]; //key保存键值,pro保存优先级,son保存儿子编号(son[x][0] , son[x][1] 分别表示 x 的左右儿子)

    (int cnt[] , sz[] ... //根据题目,增加的数据成员)

    (void Update(int x) {}... //根据题目,增加的成员函数)

    void Rotate(int &x,int t) {} //x为当前根的位置,t指示了旋转种类

    void Insert(int &x,int k) {} //x为当前位置,k为要插入的键值

    void Erase(int &x,int k) {} //x为当前位置,k为要删除的键值

  };

          

  功能简述:

  (1)旋转函数:

    (i)左旋转,根与左儿子互换位置(左儿子上提),并将左儿子的右儿子挂给根。(这可以看成给根下降作的一个“补偿”)

    (ii)右旋转,根与右儿子互换位置(右儿子上提),并将右儿子的左儿子挂给根。

  (2)插入函数:在插入的时候,需要判断插入后是否符合堆的性质,不符合则需要旋转。(注意这种旋转是递归到底层后回溯过程中不断旋转的)

  (3)删除函数:在保证其他节点满足堆的性质的情况下,将待删除节点旋转到叶子节点即可。

  拓展:

    可以通过将一个将节点的优先值设为-INF,来强制提到根,不过可能会破坏 treap 的期望深度。

 1 struct Treap{
 2     int root,tcnt;
 3     int key[MAXN],pro[MAXN],cnt[MAXN],sz[MAXN],son[MAXN][2];
 4     void clear(){
 5         root = 0;
 6         tcnt = 0;
 7         pro[0] = INF; //pro[0]用来表示空树的优先级
 8         sz[0] = 0;
 9     }
10     void Update(int x){
11         sz[x] = cnt[x] + sz[son[x][0]] + sz[son[x][1]];
12     }
13     void Rotate(int &x,int t){
14         int y = son[x][t];
15         son[x][t] = son[y][1 - t];
16         son[y][1 - t] = x;
17         Update(x);
18         Update(y);
19         x = y;
20     }
21     void _Insert(int &x,int k){
22         if(x){ //当前是非空树
23             if(key[x] == k) ++cnt[x]; //如果值重复,该数的数量加1
24             else{
25                 int t = k > key[x]; //用 t 来比较根值和待插入值
26                 _Insert(son[x][t],k);
27                 if(pro[son[x][t]] < pro[x]) Rotate(x,t); //如果插入以后导致堆的性质不满足,则旋转
28             }
29         }
30         else{ //当前是空树,那么直接插入作为根节点
31             x = ++tcnt;
32             key[x] = k;
33             cnt[x] = 1;
34             pro[x] = rand(); //随机化优先级
35             son[x][0] = son[x][1] = 0;
36         }
37         Update(x);
38     }
39     void _Erase(int &x,int k){
40         if(key[x] == k){ //找到待删除值
41             if(cnt[x] > 1) cnt[x]--;
42             else{
43                 if(son[x][0] == 0 && son[x][1] == 0){ //待删除节点无左/右儿子
44                     x = 0;
45                     return;
46                 }
47                 int t = pro[son[x][0]] > pro[son[x][1]]; //用到了空树的优先级
48                 //没有左儿子t = 1 , 没有右儿子t = 0
49                 Rotate(x,t); //优先级小的提上来
50                 _Erase(x,k); //旋转后待删除节点下移(x已经被赋值为儿子),继续向下删除
51             }
52         }
53         else    _Erase(son[x][k > key[x]],k); //未发现
54         Update(x);
55     }
56     void Insert(int k){
57         _Insert(root,k);
58     }
59     void Erase(int k){
60         _Erase(root,k);
61     }
62 }tp;

 

posted @ 2015-03-16 21:02  Naturain  阅读(126)  评论(0编辑  收藏  举报