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.
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);
}
}