树总结(二)平衡二叉树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树总结(二)平衡二叉树相关的知识,希望对你有一定的参考价值。

参考技术A

如上图所示:新插入结点 37 时,距离他最近的平衡因子绝对值超过 1 的结点是 58(58 结点左子树高度是 3 右子树高度是 1),所以从 58 开始以下的子树为 最小平衡子树

举例:
用 [3,2,1,4,5,6,7,10,9,8] 这个数组组成一个平衡二叉树。

下图图1 中。已经插入 3 个数,此时发现根结点的平衡因子变为了 2。已经是最小不平衡子树了。所以需要右转( 左子树 - 右子树 = 正数;顺势转旋转 )。如下图图2。

然后插入 4 数字。如下图图3。此时的平衡因子是 -1 符合平衡二叉树。

继续插入 5 数字。如下图图4。此时平衡被打破。结点 3 是最小不平衡子树。所以需要向左转( 左子树 - 右子树 = 负数:逆时针旋转 )。如下图图5。

继续插入数字 6 这时候发现根结点的平衡因子变为了 -2 (左子树 1 - 右子树 3)。需要逆时针旋转( 左子树 - 右子树 = 负数:逆时针旋转 )。如下图图6

旋转后发现 2 结点要放到 4 结点左子树,然而 4 结点本身存在左子树。因为这个时候 4 结点的左子树肯定比 2 结点大。所以放在 2 结点的右边。如下图图 7

继续插入数字 7 在6 结点的右子树上。5 结点的平衡因子就变为了 -2 逆时针旋转( 左子树 - 右子树 = 负数:逆时针旋转 )。结果如下图图8

继续插入数字 10 。平衡没有被打破。

继续插入数字 9 。发现平衡被打破,最小平衡子树的节点是 7 结点,最小平衡因子是 -2。应该逆时针选择( 左子树 - 右子树 = 负数:逆时针旋转 )。但是逆时针旋转完会发现,它不符合排序树,右子树比上级结点小。如下图图9

如何旋转呢?

看 7 结点的平衡因子是 -2 ,而 10 结点的平衡因子是 1 。

前面的所有旋转平衡因子要不都是正数,要不都是负数,所以先要统一两个结点平衡因子的正负号。

先旋转 10 结点子树。因为平衡因子是 1 所以顺时针转,然后在旋转最小平衡子树。如下图图10 。

继续插入数字 8。如下图图11

会发现 6 结点的平衡因子是 -2,而 9 结点的平衡因子是 1。

先旋转 9 结点的子树。9 结点的平衡因子是 1 所以顺时针( 左子树 - 右子树 = 正数;顺势转旋转 )。如下图图11

旋转后因为 7 结点有右子树,9 结点也有右子树,所以 7 结点右子树,加入 9 结点左子树。

然后在 6 结点和 7结点符号相同,如下图图12。6 结点平衡因子是 -2 所以逆时针旋转( 左子树 - 右子树 = 负数:逆时针旋转 )最终如下图图13

这里只是多加了一个 bf 平衡因子参数

这里只是旋转,不一定平衡

这里有解释一下 deepcopy 深拷贝。
因为在后面的插入时候使用递归的方法,不想 return 。
这里想直接修改传进来的 tree 这个树对象。
如果这里使用 tree = r 实际上是修改的旋转函数的内部变量 tree , 而不是 tree 对象。
这里修改 tree 对象里面的内容,这样 python 认为你在修改 tree 对象。而不是函数它自己的参数。

下图是右旋的一个图示。图中标记变量的变化过程,和平衡因子的变化

左平衡旋转和右平衡旋转

下图是左平衡旋转变量和平衡因子的变化

下图是右平衡旋转变量和平衡因子的变化

这里需要说的是在插入的递归过程中。会判断最小不平衡子树。然后根据最小不平衡子树的根结点进行旋转。

判断二叉树是否平衡二叉树

题目

平衡二叉树的性质为:要么是一颗空树,要么任何一个节点的左右子树高度差的绝对值不超过1。给定一棵二叉树的头结点head,判断这棵二叉树是否为平衡二叉树。

难度:??

基础理解

以下是个人认为对概念叙述较为详细的参考链接:

设计

概要设计

  • 设计一个初始树节点模型
  • 接收节点变量并判断是否为平衡二叉树的方法
  • 如何判断是否为平衡二叉树
    • 包含对左右各分支节点的计数器,并以此相减,是否满足绝对值 <=1 的判断方法
    • 假若左分支的左节点或右节点不满足平衡二叉树,直接退出遍历过程
  • 能改变假定 boolean 变量值的存储结构——数组

详细设计

初始树节点模型

   class Node {
        int value;
        Node left;
        Node right;

        Node(int value) {
            this.value = value;
        }
    }

布尔的判断,假定一个布尔首索引值true,通过判断平衡二叉树的具体方法将决定假定布尔值是否改变,调用该方法后,并返回布尔数组的首索引值。

    public boolean isBalance(Node node) {
        boolean[] booleans = new boolean[1];
        booleans[0] = true;
        getHeight(node, 0, booleans);
        return booleans[0];
    }

判断是否为平衡二叉树的具体方法

  • 利用自身的回调完成对节点遍历,闭包将返回值传递給变量
  • 如果(节点)左分支计数 l 减去右分支计数 r 绝对值大于1,则将数组首索引假定布尔值改变
  • 此方法的判断true或false时,所返回的整型值是多少并不重要,重要的是能否影响到假定的布尔值,这将决定整个二叉树是否为平衡二叉树
    public int getHeight(Node node, int level, boolean[] booleans) {
        if (head == null) {
            return level;
        }
        int l = getHeight(node.left, level + 1, booleans);
        int r = getHeight(node.right, level + 1, booleans);

        if (Math.abs(l - r) > 1) {
            booleans[0] = false;
        }
        return Math.max(l, r);
    }

实现

import org.junit.Test;
/**
 * @author lorem
 */
public class BalanceTreeGoTest {
    class Node {
        int value;
        Node left;
        Node right;

        Node(int value) {
            this.value = value;
        }
    }

    public boolean isBalance(Node node) {
        boolean[] booleans = new boolean[1];
        booleans[0] = true;
        getHeight(node, 0, booleans);
        return booleans[0];
    }

    public int getHeight(Node node, int level, boolean[] booleans) {
        if (node == null) {
            return level;
        }
        int l = getHeight(node.left, level + 1, booleans);
        int r = getHeight(node.right, level + 1, booleans);

        if (Math.abs(l - r) > 1) {
            booleans[0] = false;
        }
        return Math.max(l, r);
    }

    @Test
    public void test() {
        Node node = new Node(1);
        node.left = new Node(2);
        node.right = new Node(3);
        node.left.left = new Node(4);
        node.left.left.left = new Node(5);
        System.out.println(isBalance(node));
    }
}

模拟过程

以此类二叉树为例,并结合代码演示推导过程
技术分享图片
左分支推导同理
技术分享图片

以上是关于树总结(二)平衡二叉树的主要内容,如果未能解决你的问题,请参考以下文章

python判断二叉树是否为平衡二叉树

经典二叉树知识点:平衡二叉树

关于树的判定(满二叉树完全二叉树平衡二叉树相似二叉树等价二叉树)

什么是《平衡二叉树》

平衡二叉树

什么是平衡二叉树