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 ...
随机推荐
- 使用CodeFirst实现动态建库
一.业务分析 以我们平时注册今目标为例,我们在注册今目标的过程中,具体步骤是这样的: 图1 今目标登陆流程 详细解释一下: 第一步:注册界面.输入手机号或者邮箱,点击确定进入基本信息界面. 第二步:基 ...
- Python实战:爬虫的基础
网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁.自动索引.模拟程序或者蠕 ...
- 第13章 Swing程序设计----JDialog窗体
JDialog窗体是Swing组件中的对话框 JDialog窗体的功能是从一个窗体中弹出另一个窗体,就像是在使用IE浏览器时弹出的确定对话框一样. 在应用程序中创建JDialog窗体需要实例化JDia ...
- centos7 python
yum -y install gcc cd /usr/local/src wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0a1 ...
- include和 merge
include和merge标记的作用主要是为了解决layout的重用问题. 比如我们有三四个Activity但是他们都要用到同一个样式的标题栏,虽然我们把一样的代码copy个三四遍也没关系,但实在是太 ...
- SQL SERVER中强制类型转换cast和convert的区别
在SQL SERVER中,cast和convert函数都可用于类型转换,其功能是相同的, 只是语法不同. cast一般更容易使用,convert的优点是可以格式化日期和数值. 代码 select CO ...
- sql server数据库查询同义词
查询数据库同义词: select * from sys.synonyms, 查询同义词个数:select count(1) from sys.synonyms
- 1.1 selenium 安装
1.在火狐浏览器的附加组件里搜索Selenium IDE
- kinect for windows - DepthBasics-D2D详解
引自:http://blog.csdn.net/itcastcpp/article/details/20282667 Depth在kinect中经常被翻译为深度图,指的是图像到摄像头的距离,这些距离数 ...
- 解决TortoiseGit 推送 拉取需要密码的问题
找到解决了方法: 1)运行PuTTYGen,在Conversions菜单中点击Import key,选择ssh-keygen生成的私钥文件所在位置,比如id_rsa文件. 2)点击Save priva ...