大家好。
前段时间我更新过AVL、红黑树以及搜索二叉树的简单讲解。今天我们还是围绕着平衡树的话题,来讲解一个很牛逼的平衡树结构。这种结构是我国的一位大牛:陈启峰。在2006年,他还在读高中阶段,所发明的一种平衡树结构,叫Size Balanced Tree(SBT),根据节点的个数,来调整平衡性。一直到今天,这种平衡树结构,在算法竞赛领域是非常常用的,虽然SBT的时间复杂度跟AVL、红黑树这些平衡树一样,但是SBT是比较好写,比较好改的。所以在算法竞赛时,是最常用的一种算法。陈启峰SBT论文(译)
本期文章源码:GitHub

前期文章:
一、左右旋转
还是老样子,为了维持平衡性,SBT也是需要进行旋转操作的。只是说,调用旋转操作的时机,跟其他的平衡树有点区别而已。讲解旋转之前,我们先来认识SBT的节点:
//可以直接改为泛型,这里为了理解这种结构,就忽略了
public class SBTNode {
public int val; //值域
public SBTNode left, right; //左右孩子
public int size; //节点数
public SBTNode(int val) {
this.val = val;
size = 1; //默认节点大小是1
}
}
SBT的节点,只是多了一个size域,用于表示以当前节点为根节点时,这颗子树的节点数。整棵树的平衡性,就是根据这个size来调整的。
右旋转:(LL型)

旋转操作的指针,相互之间的转换,我相信以前了解过平衡树的同学,应该是知道的(如果不知道,请翻阅前期文章)。问题就在于如何,如何修改这些节点的size?
看上图,T1-T3,表示子树,另外两个表示节点,旋转之后,我们会发现,T1和T2和T3这三颗子树,他们下面的节点是没有发生改变的,也就是说T1-T3,这三个是不需要再次计算size的,我们只需要计算上图那两个白色的节点的size即可!
又因为,旋转之后,新的根节点的节点数,还应该是原根节点的节点数,所以最后我们只需要计算旋转之后,原根节点的节点数即可,也就等于该节点的左子树节点数加上右子树的节点数,再加自己本身这个节点。
//SBT右旋转
private SBTNode R_Rotate(SBTNode node) {
SBTNode newRoot = node.left;
node.left = newRoot.right;
newRoot.right = node;
//计算size
newRoot.size = node.size; //新根节点的节点数,等于原根节点的节点数
node.size = (node.left != null? node.left.size : 0) +
(node.right != null? node.right.size : 0) + 1;
return newRoot; //返回新的根节点
}
左旋转:(RR型)
跟上面的旋转一样,每个节点之间的指针指向,这里就不深究了,同学可以看看我前期的文章,有讲解。主要还是size的计算,同样的,T1~T3的节点数,都是没有变,所以不用管。只需计算原根节点和新根节点的节点数,切新根节点的节点数,就是原根节点的节点数。
//SBT左旋转操作
private SBTNode L_Rotate(SBTNode node) {
SBTNode newRoot = node.right;
node.right = newRoot.left;
newRoot.left = node;
//计算size
newRoot.size = node.size; //继承原根节点的节点数
node.size = (node.left != null? node.left.size : 0) +
(node

本文详细介绍了由高中生陈启峰在2006年发明的SizeBalancedTree(SBT),一种基于节点数量平衡的平衡树结构。SBT的核心在于Maintain方法,通过判断节点数来保持平衡,其旋转操作与AVL、红黑树类似但更易实现。文章阐述了SBT的旋转、Maintain方法以及添加和删除操作,并指出在算法竞赛中,SBT因其简单易改而常被使用。
【建议收藏】&spm=1001.2101.3001.5002&articleId=120929618&d=1&t=3&u=343249ec0da24eac85246b54c588c760)
1655

被折叠的 条评论
为什么被折叠?



