定义数据结构
struct SBT
{
int key,left,right,size;
} tree[N];
key:存储值,left,right:左右子树,size:保持平衡最终要的数据,表示子树的大小
SBT树的性质
定义一个节点x,同时满足下面两个条件
(a)、x.left.size >= max(x.right.right.size, x.right.left.size)
(b)、x.right.size >= max(x.left.left.size, x.left.right.size)
即每棵子树的大小不小于其兄弟子树的大小
结点L 和R 分别是结点T 的左右儿子。子树A;B;C;D 分别是结点L 和R 各自的左右子树。
即:R.size >= max(A.size,B.size)
L.size >= max(C.size,D.size)
旋转

左旋伪代码:
Left-Rotate (t)
1 k ← right[t]
2 right[t] ← left[k]
3 left[k] ← t
4 size[k] ← size[t]
5 size[t] ← size[left[t]] + size[right[t]] + 1
6 t ← k
void left_rot(int &x)
{
int y = tree[x].right;
tree[x].right = tree[y].left;
tree[y].left = x;
tree[y].size = tree[x].size;//转上去的节点数量为先前此处节点的size
tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
x = y;
}
右旋
Right-Rotate(t)
1 k ← left[t]
2 left[t] ← right[k]
3 right[k] ← t
4 size[k] ← size[t]
5 size[t] ← size[left[t]] + size[right[t]] + 1
6 t ← k
void right_rot(int &x)
{
int y = tree[x].left;
tree[x].left = tree[y].right;
tree[y].right = x;
tree[y].size = tree[x].size;
tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
x = y;
}
旋转只需要理解如何维护子树size即可,旋转操作不能改变二叉查找树的基本性质
维护SBT性质(Maintain)
当我们插入或删除一个结点后,SBT的大小就发生了改变。这种改变有可能导致性质(a)或(b)被破坏。这时,我们需要用
Maintain
操作来修复这棵树。
Maintain
操作是SBT中最具活力的一个独特过程;Maintain(T)用于修复以T为根的 SBT。调用Maintain(T)的前提条件是T的子树都已经是SBT了。
我们需要讨论的有4种情况。由于性质a和性质b是对称的,所以我们仅仅详细的讨论性质a。
我们需要讨论的有4种情况。由于性质a和性质b是对称的,所以我们仅仅详细的讨论性质a。
第一种情况:x.left.left.size > x.right.size
即:insert(T.left,key)后A.size > R.size
1、首先执行Right-Ratote(t),这个操作使上图变成下图;
2、在这之后,有时候这棵树还仍然不是一棵SBT,因为 s[C]>s[B] 或者 s[D]>s[B] 也是可能发生的。所以就有必要继续调用Maintain(T)。
3、结点L的右子树有可能被连续调整,因为有可能由于性质的破坏需要再一次运行Maintain(L)。
第二种情况:x.left.right.size > x.right.size
在执