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
与普通的二叉搜索树相同。向左或者向右走到底即可。
模板如下:
/* ***********************************************
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();
}
Size Balanced Tree(SBT) 模板的更多相关文章
- Size Balanced Tree(SBT树)整理
不想用treap和Splay,那就用SB树把,哈哈,其实它一点也SB,厉害着呢. 先膜拜一下作者陈启峰.Orz 以下内容由我搜集整理得来. 一.BST及其局限性 二叉查找树(Binary Search ...
- Size Balanced Tree
Size Balanced Tree(SBT)是目前速度最快的平衡二叉搜索树,且能够进行多种搜索操作,区间操作:和AVL.红黑树.伸展树.Treap类似,SBT也是通过对节点的旋转来维持树的平衡,而相 ...
- C基础 - 终结 Size Balanced Tree
引言 - 初识 Size Balanced Tree 最近在抽细碎的时间看和学习 random 的 randnet 小型网络库. iamrandom/randnet - https://github. ...
- 初学 Size Balanced Tree(bzoj3224 tyvj1728 普通平衡树)
SBT(Size Balance Tree), 即一种通过子树大小(size)保持平衡的BST SBT的基本性质是:每个节点的size大小必须大于等于其兄弟的儿子的size大小: 当我们插入或者删除一 ...
- 子树大小平衡树(Size Balanced Tree,SBT)操作模板及杂谈
基础知识(包括但不限于:二叉查找树是啥,SBT又是啥反正又不能吃,平衡树怎么旋转,等等)在这里就不(lan)予(de)赘(duo)述(xie)了. 先贴代码(数组模拟): int seed; int ...
- Size Balanced Tree(节点大小平衡树)
定义 SBT也是一种自平衡二叉查找树,它的平衡原理是每棵树的大小不小于其兄弟树的子树的大小 即size(x->l)$\ge$size(x->r->l),size(x->r-&g ...
- Size Balance Tree(SBT模板整理)
/* * tree[x].left 表示以 x 为节点的左儿子 * tree[x].right 表示以 x 为节点的右儿子 * tree[x].size 表示以 x 为根的节点的个数(大小) */ s ...
- 56. 2种方法判断二叉树是不是平衡二叉树[is balanced tree]
[本文链接] http://www.cnblogs.com/hellogiser/p/is-balanced-tree.html [题目] 输入一棵二叉树的根结点,判断该树是不是平衡二叉树.如果某二叉 ...
- Link-Cut Tree指针模板
模板: 以下为弹飞绵羊代码: #define Troy #include "bits/stdc++.h" using namespace std; ; inline int rea ...
随机推荐
- storm 使用过程中遇到的问题
1 bolt不停重启,excutor无法启动. nimbus日志类似如下(), 2014-03-12 10:55:06 b.s.d.nimbus [INFO] Executor MITAS3-74-1 ...
- 这一招让 Word 帮你自动生成文件目录,也能自动更新
学生的研究报告或是公司员工的提案企划书,为了务求严明详尽,往往是洋洋洒洒数十页或甚至上百页之多,像这样大篇幅的文件,在结构上通常会划分为好几个部分,比如像论文就会区分为封面.摘要.内文章节.参考文献等 ...
- android studio布局文件/XML怎么代码补全
android studio中的布局文件代码补全方式是打第一个字母就提示了,而java代码有时候要按快捷键. 布局文件的话呢,要写在标签开始处才提示,在标签闭合处有时候不提示,有时候在内容里也会有不提 ...
- zend笔记
ZEND_STRL(str) 等价于 (str), (sizeof(str)-1) ZEND_STRS(str)等价于 (str), (sizeof(str))
- java 数组变量与数组对象
数组是否必须初始化 对于这个问题,关键在于要弄清楚数组变量和数组对象的差别.数组变量是存放在栈内存中的,数组对象是存放在堆内存中的.数组变量只是一个引用变量,他能够指向实际的数组对象. 所谓的数组初始 ...
- VIM继承C语言(转)
在下面的基础上加上了astyle sh.c --style=kr --indent=spaces --indent-cases --pad-header --pad-oper --unpad-pare ...
- 什么是dtd文件,为什么需要
DTD为英文Document Type Definition,中文意思为“文档类定义”.DTD肩负着两重任务:一方面它帮助你编写合法的代码,另一方面它让浏览器正确地显示器代码.也许你会问它们居然有这样 ...
- 贪心<haonan>
题意: 有一列数,每次在相邻的两个书里面选择一个大数留下,同时ans+大数.问题是,求ans的最小值. 题解: 如果a[i]>a[i-1],那么ans+=a[i]; 如果a[i]>=a[i ...
- 《JavaScript高级程序设计》读书笔记 ---变量
ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据.换句话说,每个变量仅仅是一个用于保存值的占位符而已.定义变量时要使用var 操作符(注意var 是一个关键字),后 ...
- Ubuntu安装Anaconda3
下载 https://www.continuum.io/downloads#_unix Python3.5 Linux 32-bit 安装 bash Anaconda3-2.4.0-Linux-x8 ...