一 基本概念
SBT(Size Balanced Tree,节点大小平衡树)是一种自平衡二叉查找树,通过子树的大小来保持平衡。与红黑树、AVL 树等自平衡二叉查找树相比,SBT更易于实现。SBT 可以在 O (logn) 时间内完成所有二叉搜索树的相关操作,与普通二叉搜索树相比,SBT 仅加入了简洁的核心操作 maintain。由于 SBT 保持平衡的是size 域而不是其他“无用”的域,所以可以方便地实现动态顺序统计中的第 k 小和排名操作。
对 SBT 的每个节点 T,节点 L 和 R 分别是节点 T 的左右儿子,子树 A、B、C 和 D 分别是节点 L 和 R 的左右子树。T 右子树的大小都大于或等于 T 左子树两个子节点的大小,size[R]≥size[A],size[R]≥size[B];T 左子树的大小都大于或等于 T 右子树两个子节点的大小,size[L] ≥ size[C],size[L] ≥ size[D]。也就是说,“叔叔”≥“侄子”。
二 基础操作
1 右旋和左旋
SBT 的旋转也是以右旋和左旋为基础的,旋转也是 maintain 操作的基础。
(1)右旋。
x 右旋时,携带自己的右子节点向右旋转到 y 的右子树位置,y 的右子树被抛弃,x 右旋后左子树正好空闲,将 y 的右子树放在 x 的左子树上。更新 y 子树的大小等于 x 子树的大小,x 子树
的大小为其左右子树大小之和加 1。
(2)左旋。
x 左旋时,携带自己的左子节点向左旋转到 y 的左子树位置,y 的左子树被抛弃,x 左旋后右子树正好空闲,将 y 的左子树放在 x 的右子树上。更新 y 子树的大小等于 x 子树的大小,x 子树
的大小为其左右子树大小之和加 1。
2 维护
(1)LL型
一棵 SBT,若将新节点 x 插入节点 A(T 左子树的左子树)之后,节点 T 出现了不平衡(size[A]>size[R],即“侄子”大于“叔叔”),则该树属于 LL 型不平衡,需要将节点 T 右旋。
旋转之后 , A 、 B 和 R 仍 是 SBT 。 L 的右子树T可能会出现 size[C] > size[B] 或 size[D] > size[B] 的情况,即 RL、RR 型不平衡。因为 size[B] ≤ size[R],所以不会出现 B 的子树比 R 大的情况,即 T 不会出
现 LR、LL 型不平衡。因此 L 的右子树只需向右判断两种不平衡 RL、RR 即可。旋转后,L 自身也可能出现不平衡,需要继续调整平衡。
(2)LR型
有一棵 SBT,若新节点 x 插入节点B(T 左子树的右子树)之后,节点 T 出现了不平衡(size[B]>size[R]),则属于 LR 型不平衡,需要先将节点 L 左旋,然后将节点 T 右旋。
两次旋转之后,A、E、F 和 R 仍是 SBT。B 的右子树 T可能会出现 size[C]>size[F] 或 size[D]>size[F],即 RL、RR 型不平衡。因为在插
入节点之前 , size[B]≤size[R] , 插入新节点之后 ,size[B] > size[R] 。 实际上 , size[B] 最多比 size[R] 大 1 ,size[B]=size[E]+size[F]+1=size[R]+1,因此 size[F] ≤ size[R]