平衡二叉树的平衡因子只会有三种值:-1,0,1。 在平衡二叉树插入或者删除一个结点时,很可能破坏其平衡性,为了调整平衡性,因此需要执行旋转。

平衡因子

平衡因子:某结点左右子树的高度差值
【例】如下图
在这里插入图片描述

一个结点的平衡因子=该节点左子树深度-该节点右子树深度
于是:
5的结点平衡因子就是 3 - 2 = 1;
2的结点平衡因子就是 1 - 2 = -1;
4的结点平衡因子就是 1 - 0 = 1;
6的结点平衡因子就是 0 - 1 = -1;
叶子结点没有子树,于是叶子结点的平衡因子都是0


平衡二叉树和不平衡的二叉树的对比:
在这里插入图片描述

对于平衡二叉树产生了不平衡之后,如何进行平衡调整?
注意:每次都是按照最小不平衡子树进行调整

LL平衡旋转

当在某个结点的左孩子的左子树新插入了结点,需要进行LL平衡旋转,向右旋

如下图:(方框部分是对子树进行了抽象封装,同时这些子树的高度都是H,并且假设它们都是平衡的,下同)

在这里插入图片描述
上图说明:
(a) 初始状态是平衡状态,A,B结点的平衡因子分别是1,0;并且它们之间有一个潜在的大小关系:BL < B < BR < A < AR
(b) B的左子树插入了一个结点,导致A结点的平衡因子变为2,此时不满足二叉平衡树的要求(平衡因子只能是-1,0,1)
由于A结点的平衡因子为2,说明左边大,右边小,为了保持平衡,需要右旋。

在这里插入图片描述
执行右旋后,B结点的右子树会变成A结点的左子树,使得仍然满足大小关系:BL < B < BR < A < AR

*注意二叉排序树的特性:左子树结点值 < 根结点值 < 右子树结点值

( c ) 由于B的左子树增加了一个结点,使得高度加了1,此时B的平衡因子为0,又重新变成了平衡二叉树。

【例】如下图
在这里插入图片描述

插入9之后,变得不平衡,找到最小不平衡子树,由于不平衡发生在15结点的左孩子的左子树,于是需要对15的左孩子10执行LL平衡旋转,即向右旋,10替换15的位置,将15变成10的右孩子
在这里插入图片描述

RR平衡旋转

当在某个结点的右孩子的右子树插入了结点,需要进行RR平衡旋转,向左旋
在这里插入图片描述
B结点左旋到A结点的位置,为保证各节点大小顺序不变,B的左子树变为A的右子树

【例】
在这里插入图片描述
如上图所示,插入结点90后,产生了不平衡,于是先找到最小不平衡子树
在这里插入图片描述
由于不平衡发生在以66为根结点的右孩子的右子树,因此需要执行RR平衡旋转,即就是向左旋。
在这里插入图片描述

让不平衡结点66的右孩子68左旋,68替代66,为保证各结点的大小顺序不发生改变,将68的左孩子变成你66的右孩子。
在这里插入图片描述

LR平衡旋转

当在某个结点的左孩子的右子树插入了结点,需要进行LR平衡旋转,先向左旋,再向右旋

在这里插入图片描述
如上图所示,先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,将C的左子树变为B的右子树;
在这里插入图片描述

然后再把C结点向右旋转提升到A结点的位置,将C的右子树变为A的左子树

调整过后需要满足:BL<B<CL<C<CR<A<AR
【例1】
在这里插入图片描述
如上图所示,插入结点 57之后发生了不平衡,
在这里插入图片描述
最小不平衡子树为整颗树,发生不平衡的位置是 66 结点的左孩子 50 的右子树,因此需要执行LR平衡操作,针对 50 的右结点 60 先左旋,60 替代 50,50成为 60 的左孩子,原本可以60的左子树成为 50 的右子树

在这里插入图片描述
接下来右旋 ,60 代替 66 ,将 60 的右孩子变为66的左孩子
在这里插入图片描述

[例2]
在这里插入图片描述
最小不平衡子树如虚线框所示,发生在75这一结点,原因是75的左孩子38插入了右结点,因此执行LR旋转 ,找到 75 左孩子38的第一个右孩子 51,先左旋,51 提换 38,51没有子树不用为子树重新定位 ,然后 51 再右旋,51 替换 75,75 成为51的右孩子

RL平衡旋转

当在某个结点的右孩子的左子树插入了结点,需要进行RL平衡旋转,先向右旋再向左旋
在这里插入图片描述
先将A结点的右孩子B的左子树的根结点C向右旋转提升到B结点的位置,将C的右子树变为B的左子树;

然后再把C结点左旋提升到A结点的位置,将C的左子树变为A的右子树;

调整过后需要满足:AL<A<CL<C<CR<B<BR
【例】
在这里插入图片描述
插入结点 63 后,最小不平衡树仍然是整颗树,不平衡情况发生在50的右孩子的左子树 , 因此需要执行RL平衡旋转
在这里插入图片描述
在这里插入图片描述
先对结点 66 先进行右旋,66 替换 68,66的右孩子 67 成为 68 的左孩子;
然后对 66 左旋 ,66 替换 50,66 的左孩子成为 50 的右孩子;
熟练之后可以一步到位,如上图所示,66 的左子树直接给 50,右孩子直接给68, 66 往上提

为什么要按“最小不平衡子树”进行调整?

插入操作导致某个子树高度+1,当调整这个不平衡子树后,高度恢复为原来的高度后,重新恢复到平衡,其它祖先结点也自然恢复到了平衡

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐