1 概念
1.1 平衡
任何节点深度均不得过深
1.2 AVL树
每个节点的左子树和右子树高度最多差 1 的二叉查找树(空树高度定义为 -1)
带有平衡条件的二叉查找树
2 旋转
插入操作可能破坏平衡,需要通过旋转(rotation)进行修正。
设需要重新平衡的节点为 t,t 的两棵子树高度差应该为 2(平衡时高度差 <= 1)。
2.1 单旋转
对 t 的左儿子的左子树进行一次插入 / 对 t 的右儿子的右子树进行一次插入。
以对 t 的左儿子的左子树进行一次插入为例:
- 对 t 的左儿子的左子树进行插入 e,破坏了平衡
- 用 t 的左儿子 a 替换 t 作为新的根,t 作为 a 的右子树,原来 a 的右子树作为 t 的左子树
- 平衡性质恢复
2.2 双旋转
对 t 的左儿子的右子树进行一次插入 / 对 t 的右儿子的左子树进行一次插入。
双旋转等价于两次单旋转。
以对 t 的左儿子的右子树进行一次插入为例:
大写字母代表子树(E / F 可能为空),小写字母代表节点
- 对 t 的左儿子的右子树 d 进行插入,破坏了平衡
- 对 t 的左儿子的右子树进行单旋转
- 对 t 的左子树进行单旋转
- 平衡性质恢复
3 实现
AVL tree
package chapter4.avl_tree;
import chapter4.Element;
import chapter4.Node;
public class AVLTree {
private int size; //剩余节点数
private int deleteSize; //懒惰删除节点数
private Node root;
private Node min;
private Node max;
AVLTree() {
root = null;
max = null;
min = null;
}
public void clear() {
root = null;
}
public boolean isEmpty() {
return root == null;
}
public boolean contains(Element x) {
return contains(x, root);
}
public void insert(Element x) {
root = insert(x, root);
}
public void remove(Element x) {
remove(x, root);
}
public Element findMin() {
findMin(root);
return min.element;
}
public Element findMax() {
findMax(root);
return max.element;
}
public void printTree() {
printTree(root);
}
private boolean contains(Element x, Node t) {
if (t == null) {
return false;
}
int comp = x.compareTo(t.element);
if (comp > 0) { //大于节点值,右子树中搜索
return contains(x, t.right);
} else if (comp < 0) { //小于节点值,左子树中搜索
return contains(x, t.left);
} else {
return true;
}
}
private Node insert(Element x, Node t) {
if (t == null) {
return new Node(x);
}
int comp = x.compareTo(t.element);
if (comp > 0) { //大于节点值,右子树中插入
t.right = insert(x, t.right);
if (height(t.right) - height(t.left) == 2) {
if (x.compareTo(t.right.element) > 0) { //右儿子的右子树