PAT1066 平衡二叉树的根节点

1066 Root of AVL Tree (25分)

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

img img

img img

Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the root of the resulting AVL tree in one line.

Sample Input 1:

5
88 70 61 96 120  

Sample Output 1:

70  

Sample Input 2:

7
88 70 61 96 120 90 65  

Sample Output 2:

88   

题目大意:

题意是比较清楚的,就是给我们一个整数序列,按照这个序列进行AVL 树的插入,最后得到的这颗树的根节点的值是多少。

思路分析:

这个题的重点就是平衡二叉树的插入,基本的情况和二分搜索树类似,多了平衡调整。对于一棵平衡二叉树来说,他的任意一个节点的左右子树的高度差不能超过1。 因此,在Node节点的设计中,我们需要为每一个节点加入一个 height属性标记节点在树中的高度,初始值为1 ,如果节点为空,高度定义为0.

其次是平衡因子: 通常我们把一个节点的平衡因子定义为 该节点的左子树的高度-该节点的右子树高度。最后对于不平衡的现象,如何调整使得平衡。通常的不平衡现象主要有四种。(1)下图中,节点y 发生了不平衡,此时 y 的平衡因子 > 1(左子树比右子树高) 并且 y的左孩子的平衡因子>=0 。 下图中没有画出x的平衡因子=0 的情况。 实际上如果T1,T2,T4为空,我们就可以发现y的平衡因子为2 x为0 依然需要调整。对于这中 balanceFactor(y) > 1 && balcenFactor(x)>=0 的情况,做法是对不平衡节点y 进行右旋转。 具体的做法是: x.right = y , y.left = T3

              y(2)                           x
             / \                           /   \
         (1)x   T4     向右旋转 (y)        z     y
           / \       - - - - - - - ->    / \   / \
          z   T3                       T1  T2 T3 T4
         / \
       T1   T2

与右旋转对应的情况是左旋转。对应的平衡因子的特征是: balanceFactor(y) <-1 并且 balacneFactor( x ) <=0 具体的调整过程是:x.left = y , y.right = T2

          y                             x
        /  \                          /   \
       T1   x      向左旋转 (y)       y     z
           / \   - - - - - - - ->   / \   / \
          T2  z                     T1 T2 T3 T4
             / \
            T3 T4

还有两种情况并不能一次调整就能完成,如下所示:z这种造成y 不平衡的troublemaker 在y的左子树的右子树中,balanceFactor(y) >1 并且 balanceFactor(x) <0 .此时无论对y 进行坐旋转还是右旋转 都不行。 通常的旋转操作是,先对 x 进行左旋转 ,然后对y进行右旋转。 通常称为 LR双旋。三者的大小关系为 x < z < y 可以看到两次旋转,这个关系都没有打破。说明旋转都是合法操作。

       y                 y                        
      /                 /                        z
     x    -------     z        -----------     /   \
      \              /                        x     y
       z            x 

有了上面这种情况,就有对称的下面这种情况, 我们要做的就是 先对x 进行右旋转,然后对 y进行左旋转。对应的平衡因子的特征是: balanceFactor(y)> 1 并且 balanceFactor(x) >0

      y                  y                   
        \                 \                       z
          x    ------       z       -------     /   \
        /                    \                 y      x
      z                       x

完整代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class P1066 {
    static class Node {
        int val;
        Node left, right;
        int height;

        public Node(int val) {
            this.val = val;
            this.left = this.right = null;
            this.height = 1; // 初始的高度都赋值为1
        }
    }

    // 返回节点的高度
    static int getHeight(Node node) {
        if (node == null)
            return 0;
        else
            return node.height;
    }

    // 返回节点的平衡因子
    static int getBalanceFactor(Node node) {
        if (node == null)
            return 0;
        return getHeight(node.left) - getHeight(node.right);
    }

    // 向以root 为根节点的AvL 树中添加一个value
    static Node add(Node root, int val) {
        if (root == null) {
            return new Node(val);
        }
        if (val < root.val) {

            root.left = add(root.left, val);
        }
        if (val > root.val) {
            root.right = add(root.right, val);
        }

        // 计算高度
        root.height = 1 + Math.max(getHeight(root.left), getHeight(root.right));
        int balanceFactor = getBalanceFactor(root);
        // LL 模式
        if (balanceFactor > 1 && getBalanceFactor(root.left) >= 0) {
            return rightRoate(root);
        }
        // RR模式
        if (balanceFactor < -1 && getBalanceFactor(root.right) <= 0) {
            return leftRoate(root);
        }
        // LR模式
        if (balanceFactor > 1 && getBalanceFactor(root.left) < 0) {
            root.left = leftRoate(root.left);
            return rightRoate(root);
        }
        // RL模式
        if (balanceFactor < -1 && getBalanceFactor(root.right) > 0) {
            root.right = rightRoate(root.right);
            return leftRoate(root);
        }

        return root;
    }

    // 右旋转 不要忘了暂存节点
    static Node rightRoate(Node y) {
        Node x = y.left;
        Node t = x.right;
        //旋转
        x.right = y;
        y.left = t;
        // 更新高度 先更新y 因为旋转后 x 在y的上面
        y.height = 1 + Math.max(getHeight(y.left), getHeight(y.right));
        x.height = 1 + Math.max(getHeight(x.right), getHeight(x.left));
        return x;
    }

    // 左旋转
    static Node leftRoate(Node y) {
        Node x = y.right;
        Node t = x.left;
        // 旋转
        x.left = y;
        y.right = t;
        // 更新高度
        y.height = 1 + Math.max(getHeight(y.right), getHeight(y.left));
        x.height = 1 + Math.max(getHeight(x.left), getHeight(x.right));
        return x;
    }


    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int num = Integer.parseInt(bf.readLine());
        int[] data = new int[num];
        String[] values = bf.readLine().split(" ");
        for (int i = 0; i < num; i++)
            data[i] = Integer.parseInt(values[i]); // 存储待插入序列

        Node root = null;
        for (int i = 0; i < num; i++) { //将所有数字 一一存储AVL 树中
            root = add(root, data[i]);
        }
        System.out.print(root.val);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值