数据结构-平衡二叉树示例

1 平衡二叉树简介

  平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树,它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子BF( Balance Factor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1,0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。
  距离插入结点最近的,且平衡因子的绝对值大于1的结点为根的子树,我们称为最小不平衡子树

2 平衡二叉树示例

  我们希望由任何初始序列构成的二叉排序树都是AVL树。因为AVL树上任何结点的左右子树的深度之差都不超过1,则可以证明它的深度和 logn 是同数量级的(其中n为结点个数)。由此,它的平均查找长度也和logn同数量级。
  平衡二叉树构建的基本思想就是在构建二叉排序树的过程中,每当插入一个结点时,先检查是否因插入而破坏了树的平衡性,若是,则找出最小不平衡子树。在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的连接关系,进行相应的旋转,使之成为新的平衡子树。如何使构成的二叉排序树成为平衡树呢?看一个具体例子,假设有一个数组关键字序列为(3,2,1,4,5,6,7,10,9,8),其中结点左上角的数字是平衡因子BF的值。

  1、第一个关键字是“3”,直接构建为根结点,如图2-1的左图所示。

    此时结点“3”的BF0(左孩子0 - 右孩子0 = 0

  2、第二个关键字是“2”,关键字“2”比关键字“3”小,所以成为“3”的左孩子,如图2-1的右图所示。

    此时结点“3”的BF1(左孩子1 - 右孩子0 = 1)
    此时结点“2”的BF0(左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-1

  3、第三个关键字是“1”,关键字“1”比关键字“2”小,所以成为“2”的左孩子,此时关键字“3”的BF不在平衡因子的取值范围内,此时整棵树都成了最小不平衡子树,因此需要调整,因为关键字“3”的BF值为正,因此我们将整个树进行右旋(顺时针旋转),此时结点“2”成了根结点,结点“3”成了结点“2”的右孩子,此时三个结点的BF值均为0,如图2-2所示。

    此时结点“3”的BF2(左孩子2 - 右孩子0 = 2)
    此时结点“2”的BF1(左孩子1 - 右孩子0 = 1)
    此时结点“1”的BF0(左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-2
  4、第四个关键字是“4”,关键字“4”比关键字“3”大,所以成为“3”的右孩子,此时三个结点的BF值均在平衡因子的取值范围内,不用对树进行任何调整,如图2-3所示。
    此时结点“2”的BF-1(左孩子1 - 右孩子2 = -1)
    此时结点“3”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-3

  5、第五个关键字是“5”,关键字“5”比关键字“4”大,所以成为“4”的右孩子,此时关键字“3”的BF不在平衡因子的取值范围内,此时要对最小不平衡子树(3、4、5)进行旋转,因为关键字“3”的BF值为负,因此我们将对最小不平衡子树进行左旋(逆时针旋转),旋转后结点“3”成了结点“4”的左孩子,整个树又达到了平衡,如图2-4所示。

    此时结点“3”的BF-2(左孩子0 - 右孩子2 = -2)
    此时结点“2”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-4

  6、第六个关键字是“6”,关键字“6”比关键字“5”大,所以成为“5”的右孩子,此时关键字“2”的BF不在平衡因子的取值范围内,此时要对最小不平衡子树进行旋转,因为关键字“2”的BF值为负,因此我们将对最小不平衡子树进行左旋(逆时针旋转),旋转后结点“4”成了根结点,结点“3”成了结点“2”的右孩子,整个树又达到了平衡,如图2-5所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-1(左孩子1 - 右孩子2 = -1)
    此时结点“5”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“6”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-5

  7、第七个关键字是“7”,关键字“7”比关键字“6”大,所以成为“6”的右孩子,此时关键字“5”的BF不在平衡因子的取值范围内,此时要对最小不平衡子树(5、6、7)进行旋转,因为关键字“5”的BF值为负,因此我们将对最小不平衡子树进行左旋(逆时针旋转),旋转后结点“5”成了结点“6”的左孩子,整个树又达到了平衡,如图2-6所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-1(左孩子2 - 右孩子3 = -1)
    此时结点“5”的BF-2(左孩子0 - 右孩子2 = -2)
    此时结点“6”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“7”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-6

  8、第八个关键字是“10”,关键字“10”比关键字“7”大,所以成为“7”的右孩子,此时整个树是平衡状态,不需要旋转调整,如图2-7所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-1(左孩子2 - 右孩子3 = -1)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“6”的BF-1(左孩子1 - 右孩子2 = -1)
    此时结点“7”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“10”的BF0(左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-7

  9、第九个关键字是“9”,关键字“9”比关键字“10”小,所以成为“10”的左孩子,此时关键字“7”的BF不在平衡因子的取值范围内,此时要对最小不平衡子树(7、10、9)进行旋转,但是若简单因为关键字“7”的BF值为负,因此我们将对最小不平衡子树进行左旋(逆时针旋转)后使得结点“9”成了结点“10”的右孩子,这是不符合二叉排序树特性的,此时不能简单的左旋。
  根本原因在于结点“7”的BF是-2,而结点“10”的BF是1,也就是说他们俩一正一负,符号并不统一,而前面几次旋转,无论是左旋还是右旋,最小不平衡子树的根结点与它的子结点符号都是相同的,这就是不能直接旋转的原因。
  既然是符号不统一,那就先旋转到符号统一后再说,于是先对结点“9”和结点“10”进行右旋,使得结点“10”成为结点“9”的右子树,此时结点“9”的BF为-1,就与结点“7”的BF值符号统一了,如图2-8所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-2(左孩子2 - 右孩子4 = -2)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“6”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“7”的BF-2(左孩子0 - 右孩子2 = -2)
    此时结点“10”的BF1(左孩子1 - 右孩子0 = 1)
    此时结点“9”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-8

  再以结点“7”为最小不平衡子树进行左旋,旋转后结点“7”成了结点“9”的左孩子,整个树又达到了平衡,如图2-9所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-2(左孩子2 - 右孩子4 = -2)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“6”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“7”的BF-2(左孩子0 - 右孩子2 = -2)
    此时结点“10”的BF0(左孩子0 - 右孩子0 = 0)
    此时结点“9”的BF-1(左孩子0 - 右孩子1 = -1

在这里插入图片描述

图2-9

  10、第十个关键字是“8”,关键字“8”比关键字“7”大,所以成为“7”的右孩子,此时关键字“6”的BF不在平衡因子的取值范围内,此时要对最小不平衡子树(7、8、9、10)进行旋转,此时结点“6”的BF是-2,而结点“9”的BF是1,也就是说他们俩一正一负,符号并不统一,同上还是先旋转到符号统一后再说,于是先对最小不平衡子树(7、8、9、10)进行右旋,使得结点“9”成为结点“7”的子树,结点“8”成为结点“9”的左孩子,此时结点“7”的BF为-2,就与结点“6”的BF值符号统一了,如图2-10所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-2(左孩子2 - 右孩子4 = -2)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“6”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“7”的BF-1(左孩子0 - 右孩子1 = -1)
    此时结点“10”的BF0(左孩子0 - 右孩子0 = 0)
    此时结点“9”的BF1 (左孩子2 - 右孩子1 = 1)
    此时结点“8”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-10

  再以结点“7”为最小不平衡子树进行左旋,旋转后结点“7”成了根结点,结点“6”成了结点“7”的左孩子,整个树又达到了平衡,如图2-11所示。

    此时结点“3”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“2”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“1”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“4”的BF-2(左孩子2 - 右孩子4 = -2)
    此时结点“5”的BF0 (左孩子0 - 右孩子0 = 0)
    此时结点“6”的BF-2(左孩子1 - 右孩子3 = -2)
    此时结点“7”的BF-2(左孩子0 - 右孩子2 = -2)
    此时结点“10”的BF0(左孩子0 - 右孩子0 = 0)
    此时结点“9”的BF0 (左孩子1 - 右孩子1 = 0)
    此时结点“8”的BF0 (左孩子0 - 右孩子0 = 0

在这里插入图片描述

图2-11

3 总结

  通过上述这个例子会发现,当最小不平衡子树根结点的平衡因子BF大于1时,就右旋,小于-1时,就左旋,插入结点后,最小不平衡子树的BF与它的子树的BF符号相反时,就需要对结点先进行一次旋转以使得符号相同后,再反向旋转一次才能够完成平衡操作,其中先进行一次旋转是以子树的正负决定的旋转方向,例如结点“9”的操作,先进行右旋是因为结点“10”的BF是“1”,再例如结点“8”的操作,先进行右旋是因为结点“9”的BF是“1”。

  ------以上过程参考《大话数据结构》中“平衡二叉树”内容。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值