一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1)。
重点在于:
插入和删除可能破坏AVL树的平衡特性,需要进行平衡
分为四种情况:
假设重新平衡的节点为a
需要进行单旋转
(1)a的左儿子的左子树插入
(2)a的右儿子的右子树插入需要进行双旋转
(3)a的左儿子的右子树插入
(4)a的右儿子的左子树插入
package com.base;
public class AvlTree<Item extends Comparable<? super Item>> {
private static class Node<Item> {
Node(Item item) {
this(item, null, null);
}
Node(Item item, Node<Item> lt, Node<Item> rt) {
this.item = item;
this.left = lt;
this.right = rt;
this.height = 0;
}
private Item item;
private Node<Item> left;
private Node<Item> right;
private int height; // 高度
}
private Node<Item> root;
public AvlTree() {
root = null;
}
public void clear() {
root = null;
}
public boolean isEmpty() {
return root == null;
}
/*
* 查找最小
*/
public Item min() throws Exception {
if (isEmpty()) // 树为空的情况
throw new Exception();
return min(root).item;
}
private Node<Item> min(Node<Item> t) {
if (t == null)
return t;
while (t.left != null) // 非递归方法
t = t.left;
return t;
}
/*
* 查找最大
*/
public Item max() throws Exception {
if (isEmpty())
throw new Exception();
return max(root).item;
}
private Node<Item> max(Node<Item> t) { // 递归方法
if (t.left == null)
return t;
else
return min(t.left);
}
/*
* 是否包含
*/
public boolean contains(Item x) {
return contains(x, root);
}
private boolean contains(Item x, Node<Item> t) {
while (t != null) { // 非递归方式
int cmp = x.compareTo(t.item);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return true; // 匹配
}
return false; // 不包含
}
// 遍历
public void printTree() {
if (isEmpty())
System.out.println("Empty tree");
else
printTree(root);
}
private void printTree(Node<Item> t) { // 左根右--中序
if (t != null) {
printTree(t.left);
System.out.println(t.item);
printTree(t.right);
}
}
/*
* 插入
*/
public void insert(Item x) {
root = insert(x, root);
}
private Node<Item> insert(Item x, Node<Item> t) {
if (t == null) // root为null的情况
return new Node<>(x, null, null);
int cmp = x.compareTo(t.item);
if (cmp < 0)
t.left = insert(x, t.left);
else if (cmp > 0)
t.right = insert(x, t.right);
else
; // 正常二叉树插入
return balance(t); // 再平衡
}
/*
* 删除
*/
public void remove(Item x) {
root = remove(x, root);
}
private Node<Item> remove(Item x, Node<Item> t) {
if (t == null)
return t;
int cmp = x.compareTo(t.item);
if (cmp < 0)
t.left = remove(x, t.left);
else if (cmp > 0)
t.right = remove(x, t.right);
else {
if (t.right == null)
return t.left;
if (t.left == null)
return t.right;
t.item = min(t.right).item;
t.right = remove(t.item, t.right);
}
return balance(t); // 正常二叉树删除后再平衡
}
// AVL平衡树
// 每个节点的左子树和右子树的高度最多差 1
private static final int ALLOWED_IMBALANCE = 1;
// 平衡二叉树
private Node<Item> balance(Node<Item> t) {
if (t == null)
return t;
if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) // 左儿子
if (height(t.left.left) >= height(t.left.right))
t = rotateWithLeftChild(t); // 左儿子的左子树(单旋转)
else
t = doubleWithLeftChild(t); // 左儿子的右子树(双旋转)
else if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) // 右儿子
if (height(t.right.right) >= height(t.right.left))
t = rotateWithRightChild(t); // 右儿子的右子树(单旋转)
else
t = doubleWithRightChild(t); // 右儿子的左子树(双旋转)
t.height = Math.max(height(t.left), height(t.right)) + 1; // 更新二叉树高度
return t;
}
/*
* 二叉树高度--树null,高度为-1
*/
private int height(Node<Item> t) {
return t == null ? -1 : t.height;
}
/*
* 把左边的树变成右边的树
*/
private Node<Item> rotateWithLeftChild(Node<Item> k2) {
Node<Item> k1 = k2.left;
k2.left = k1.right;
k1.right = k2; // k1 变为根
k2.height = Math.max(height(k2.left), height(k2.right)) + 1; // k2 高度
k1.height = Math.max(height(k1.left), k2.height) + 1; // 根k1 高度
return k1;
}
/*
* 右边的树变为左边的树
*/
private Node<Item> rotateWithRightChild(Node<Item> k1) {
Node<Item> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.right), k1.height) + 1;
return k2;
}
/*
* 左儿子的右子树
*/
private Node<Item> doubleWithLeftChild(Node<Item> k3) {
k3.left = rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
/*
* 右儿子的左子树
*/
private Node<Item> doubleWithRightChild(Node<Item> k1) {
k1.right = rotateWithLeftChild(k1.right);
return rotateWithRightChild(k1);
}
/*
* 检查二叉树是否平衡
*/
public void checkBalance() {
checkBalance(root);
}
private int checkBalance(Node<Item> t) {
if (t == null)
return -1;
if (t != null) {
int hl = checkBalance(t.left);
int hr = checkBalance(t.right);
if (Math.abs(height(t.left) - height(t.right)) > 1 || height(t.left) != hl || height(t.right) != hr)
System.out.println("不平衡");
}
return height(t);
}
}
一点一点补充吧
-