竞赛最好用的平衡树-Size Balanced Tree(SBT)【建议收藏】

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

大家好。

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

本期文章源码:GitHub

img

前期文章

二叉树的概念以及搜索二叉树

AVL平衡树

浅析红黑树

一、左右旋转

还是老样子,为了维持平衡性,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型)

image-20211023155252766

旋转操作的指针,相互之间的转换,我相信以前了解过平衡树的同学,应该是知道的(如果不知道,请翻阅前期文章)。问题就在于如何,如何修改这些节点的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
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听雨7x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值