Size Balanced Tree(SBT) 模板

时间:2023-03-09 03:31:33
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]]].

Size Balanced Tree(SBT) 模板

即在上图中:

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

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

模板如下:

 /* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : Size Balanced Tree
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; #define MAXN 1000 typedef struct sbtnod
{
int key,left,right,size;
} sbtnode;
int sbttail,sbt; sbtnode tree[MAXN]; void rrotate(int& t)
{
int k=tree[t].left;
if (!k) return ;
tree[t].left=tree[k].right;
tree[k].right=t;
tree[k].size=tree[t].size;
tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+;
t=k;
} void lrotate(int& t)
{
int k=tree[t].right;
if (!k) return ;
tree[t].right=tree[k].left;
tree[k].left=t;
tree[k].size=tree[t].size;
tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+;
t=k;
} void maintain(int& t,bool flag)
{
if (!t) return ;
if (!flag)
if (tree[tree[tree[t].left].left].size>tree[tree[t].right].size) rrotate(t);
else if (tree[tree[tree[t].left].right].size>tree[tree[t].right].size)
{
lrotate(tree[t].left);
rrotate(t);
} else return ;
else
if (tree[tree[tree[t].right].right].size>tree[tree[t].left].size) lrotate(t);
else if (tree[tree[tree[t].right].left].size>tree[tree[t].left].size)
{
rrotate(tree[t].right);
lrotate(t);
} else return ; maintain(tree[t].left,false);
maintain(tree[t].right,true);
maintain(t,false);
maintain(t,true);
} void insert(int& t,int v)
{
if (!t)
{
sbttail++;
tree[sbttail].key=v;
tree[sbttail].size=;
t=sbttail;
} else
{
tree[t].size++;
if (v<tree[t].key) insert(tree[t].left,v);
else insert(tree[t].right,v);
maintain(t,v>=tree[t].key);
}
} int del(int& t,int v)
{
int ret;
tree[t].size--;
if (v==tree[t].key||(v<tree[t].key&&tree[t].left==)||(v>tree[t].key&&tree[t].right==))
{
ret=tree[t].key;
if (tree[t].left==||tree[t].right==) t=tree[t].left+tree[t].right;//
else tree[t].key=del(tree[t].left,tree[t].key+);
} else
{
if (v<tree[t].key) ret=del(tree[t].left,v);
else ret=del(tree[t].right,v);
}
return ret;
} int select(int t,int k)
{
if (k==tree[tree[t].left].size+) return t;
if (k<=tree[tree[t].left].size) return select(tree[t].left,k);
else return select(tree[t].right,k--tree[tree[t].left].size);
} int search(int t,int x)
{
if (t==||x==tree[t].key) return t;
if (x<tree[t].key) return search(tree[t].left,x);
else return search(tree[t].right,x);
} int getmin(int t)
{
int i=t;
while(tree[i].left)
{
i=tree[i].left;
}
return i;
} int getmax(int t)
{
int i=t;
while(tree[i].right)
{
i=tree[i].right;
}
return i;
} int pred(int& t,int y,int v)
{
if (!t) return y;
if (tree[t].key<v) return pred(tree[t].right,t,v);
else return pred(tree[t].left,y,v);
} int succ(int& t,int y,int v)
{
if (!t) return y;
if (tree[t].key>=v) return succ(tree[t].left,t,v);
else return succ(tree[t].right,y,v);
} void deb_out()
{
printf("-------\n");
printf("sbttail=%d sbt=%d\n",sbttail,sbt);
for (int i=;i<=sbttail;i++)
printf("%2d: key=%2d size=%2d left=%2d right=%2d\n",i,tree[i].key,tree[i].size,tree[i].left,tree[i].right);
printf("-------\n");
} int main()
{
memset(tree,,sizeof(tree));
sbttail=;
sbt=; for (int i=;i<=;i++) insert(sbt,i);
deb_out(); //printf("%d\n",del(sbt,8));
insert(sbt,);
deb_out();
del(sbt,);
del(sbt,);
printf("%d\n",search(sbt,));
deb_out();
}