zoukankan      html  css  js  c++  java
  • Size Balanced Tree(SBT) 模板

    首先是从二叉搜索树开始,一棵二叉搜索树的定义是:

    1.这是一棵二叉树;

    2.令x为二叉树中某个结点上表示的值,那么其左子树上所有结点的值都要不大于x,其右子树上所有结点的值都要不小于x。

    由二叉搜索树的第二条定义,可以很方便地利用这种特点在二叉树中以O(logn)的渐进复杂度完成插入、查找、删除等操作。

    但是这里还是有个问题,就是弄不好的话,一棵普通的二叉搜索树经过多次修改操作之后可能会导致整棵树左右“不平衡”,出现一边结点很多,另一边结点很少的情况,这样最终每一次的操作时间就会大大偏离O(logn),甚至最后退化成一条链。

    平衡树就是通过一系列的操作,不断动态维持二叉搜索树的左右平衡,始终保证二叉搜索树的效率。

    SBT全称Size Balanced Tree,是一种通过记录以每个结点为根的子树中的结点的个数size,然后进行二叉搜索树结构调整的方法,由OI选手陈启峰发明。

    SBT除了一般的二叉搜索树性质之外,还有两条性质:

    对于SBT中的每一个结点t,有:

    1.s[right[t]]>=s[left[left[t]]],s[right[left[t]]];

    2.s[left[t]]>=s[left[right[t]]],s[right[right[t]]].

    即在上图中:

    s[L]>=s[C],s[D];s[R]>=s[A],s[B].

    这一性质能够保证整棵SBT能够在整体的结构上保持相对平衡,而为了保持这一额外的性质,需要通过不断的调整来完成。

    调整即通过结点的左右旋完成,左右旋不改变二叉搜索树的性质,而能够调整SBT的size,使得整棵树能够始终保持为一棵SBT树。

    • 保持-maintain

    这是SBT的核心操作,保持过程通过左右旋来完成。

    • 插入-insert

    与普通的二叉搜索树相同,只是在插入完之后加入一个maintain操作。

    • 删除-del

    与普通的二叉搜索树相同。删除完一个结点之后虽然不能够保证此时的树还能够严格保持SBT性质,但是树结构从整体上来说最大深度不会增加,因此maintain操作就不需要进行了。

    • 查找值-search

    与普通的二叉搜索树相同。

    • 查找第k个-select

    由于size的存在,SBT天生就很适合处理查找第k个数这样的任务。不断确定一下左子树和右子树的size即可,若某结点左子树的size+1=k,那么该结点就是第k个数。

    • 查找前趋/后继-pred/succ

    与普通的二叉搜索树相同。

    经过实际情况的分析,SBT中由于左右旋操作的存在,并不能严格保证与当前节点值相等的是在左边还是右边!!!因而应该不能够按照普通二叉搜索树的写法写......具体应该怎么写我还没有想到比较合适的方法(唉...囧...找了不少资料也基本上对这个都没怎么讲清楚)。下面贴的模板代码的pred和succ应该都是不合适的。

    • 获取最大/最小值-getmax/getmin

    与普通的二叉搜索树相同。向左或者向右走到底即可。

    模板如下:

      1 /* ***********************************************
      2 MYID    : Chen Fan
      3 LANG    : G++
      4 PROG    : Size Balanced Tree
      5 ************************************************ */
      6 
      7 #include <iostream>
      8 #include <cstdio>
      9 #include <cstring>
     10 #include <algorithm>
     11 
     12 using namespace std;
     13 
     14 #define MAXN 1000
     15 
     16 typedef struct sbtnod
     17 {
     18     int key,left,right,size;
     19 } sbtnode;
     20 int sbttail,sbt;
     21 
     22 sbtnode tree[MAXN];
     23 
     24 void rrotate(int& t)
     25 {
     26     int k=tree[t].left;
     27     if (!k) return ;
     28     tree[t].left=tree[k].right;
     29     tree[k].right=t;
     30     tree[k].size=tree[t].size;
     31     tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1;
     32     t=k;
     33 }
     34 
     35 void lrotate(int& t)
     36 {
     37     int k=tree[t].right;
     38     if (!k) return ;
     39     tree[t].right=tree[k].left;
     40     tree[k].left=t;
     41     tree[k].size=tree[t].size;
     42     tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1;
     43     t=k;
     44 }
     45 
     46 void maintain(int& t,bool flag)
     47 {
     48     if (!t) return ;
     49     if (!flag)
     50         if (tree[tree[tree[t].left].left].size>tree[tree[t].right].size) rrotate(t);
     51         else if (tree[tree[tree[t].left].right].size>tree[tree[t].right].size) 
     52         {
     53             lrotate(tree[t].left);
     54             rrotate(t);
     55         } else return ;
     56     else
     57         if (tree[tree[tree[t].right].right].size>tree[tree[t].left].size) lrotate(t);
     58         else if (tree[tree[tree[t].right].left].size>tree[tree[t].left].size)
     59         {
     60             rrotate(tree[t].right);
     61             lrotate(t);
     62         } else return ;
     63     
     64     maintain(tree[t].left,false);
     65     maintain(tree[t].right,true);
     66     maintain(t,false);
     67     maintain(t,true);
     68 }
     69 
     70 void insert(int& t,int v)
     71 {
     72     if (!t)
     73     {
     74         sbttail++;
     75         tree[sbttail].key=v;
     76         tree[sbttail].size=1;
     77         t=sbttail;
     78     } else 
     79     {
     80         tree[t].size++;
     81         if (v<tree[t].key) insert(tree[t].left,v);
     82         else insert(tree[t].right,v);
     83         maintain(t,v>=tree[t].key);
     84     }
     85 }
     86 
     87 int del(int& t,int v)
     88 {
     89     int ret;
     90     tree[t].size--;
     91     if (v==tree[t].key||(v<tree[t].key&&tree[t].left==0)||(v>tree[t].key&&tree[t].right==0))
     92     {
     93         ret=tree[t].key;
     94         if (tree[t].left==0||tree[t].right==0) t=tree[t].left+tree[t].right;//
     95         else tree[t].key=del(tree[t].left,tree[t].key+1);
     96     } else 
     97     {
     98         if (v<tree[t].key) ret=del(tree[t].left,v);
     99         else ret=del(tree[t].right,v);
    100     }
    101     return ret;
    102 }
    103 
    104 int select(int t,int k)
    105 {
    106     if (k==tree[tree[t].left].size+1) return t;
    107     if (k<=tree[tree[t].left].size) return select(tree[t].left,k);
    108     else return select(tree[t].right,k-1-tree[tree[t].left].size);
    109 }
    110 
    111 int search(int t,int x)
    112 {
    113     if (t==0||x==tree[t].key) return t;
    114     if (x<tree[t].key) return search(tree[t].left,x);
    115     else return search(tree[t].right,x);
    116 }
    117 
    118 int getmin(int t)
    119 {
    120     int i=t;
    121     while(tree[i].left)
    122     {
    123         i=tree[i].left;
    124     }
    125     return i;
    126 }
    127 
    128 int getmax(int t)
    129 {
    130     int i=t;
    131     while(tree[i].right)
    132     {
    133         i=tree[i].right;
    134     }
    135     return i;
    136 }
    137 
    138 int pred(int& t,int y,int v)
    139 {
    140     if (!t) return y;
    141     if (tree[t].key<v) return pred(tree[t].right,t,v);
    142     else return pred(tree[t].left,y,v);
    143 }
    144 
    145 int succ(int& t,int y,int v)
    146 {
    147     if (!t) return y;
    148     if (tree[t].key>=v) return succ(tree[t].left,t,v);
    149     else return succ(tree[t].right,y,v);
    150 }
    151 
    152 void deb_out()
    153 {
    154     printf("-------
    ");
    155     printf("sbttail=%d sbt=%d
    ",sbttail,sbt);
    156     for    (int i=1;i<=sbttail;i++)
    157     printf("%2d: key=%2d size=%2d left=%2d right=%2d
    ",i,tree[i].key,tree[i].size,tree[i].left,tree[i].right);
    158     printf("-------
    ");
    159 }
    160 
    161 int main()
    162 {
    163     memset(tree,0,sizeof(tree));
    164     sbttail=0;
    165     sbt=0;
    166     
    167     for    (int i=1;i<=15;i++) insert(sbt,i);
    168     deb_out();
    169     
    170     //printf("%d
    ",del(sbt,8));
    171     insert(sbt,8);
    172     deb_out();
    173     del(sbt,8);
    174     del(sbt,8);
    175     printf("%d
    ",search(sbt,8));
    176     deb_out();
    177 }
  • 相关阅读:
    关于linux命令 cp,rm,mv执行时是否询问的问题,不同用户有不同的别名设置
    用jquery根据json动态创建多级菜单导航(by https://www.cnblogs.com/fatty-yu/p/7088955.html)
    前台向后台传值的两种方法 以及 从后台获取数据的方法
    “加载更多”功能如何实现
    AngularJS的主要组成部分:
    数组与字符串的相互转化
    angular过滤器的使用 By http://www.tuicool.com/articles/ueUZBv
    transclude
    内嵌模版 template 原创
    导航栏选中效果 ng-repeat
  • 原文地址:https://www.cnblogs.com/jcf94/p/4323571.html
Copyright © 2011-2022 走看看