GitHub源码地址:(https://github.com/BradenLei/AVL)
1、基本概念及操作:
1)平衡二叉查找树:在二叉查找树的基础上满足平衡因子为-1,0,1的树结构
2)平衡因子:右子树的高度减去左子树的高度;-1表示左偏重,+1表示右偏重
3)重新平衡数:从AVL树中插入或者删除一个元素后,如果树变得不平衡了,执行一次旋转操作来重新平衡该树,有四种方式:
LL旋转、RR旋转、LR旋转、RL旋转
以 LL说明:两个L表示两次左偏重
4)AVL树的设计:由于AVL树是二叉查找树,AVLTree设计为BST的子类(BST实现在上一篇博文中,这里不再累述)
5)重写insert、delete方法:AVL树中的这两操作基本一致,不同之处在于树可能需要重新平衡。
6)AVL树的高度为O(logn),所以其search、insert以及delete方法的时间复杂度为O(logn)
AVL实现:
package binary;
import java.util.ArrayList;
public class AVLTree<E extends Comparable<E>> extends BST<E> {
public AVLTree() {
}
public AVLTree(E[] objects) {
super(objects);
}
@Override
protected AVLTreeNode<E> createNewNode(E e){
return new AVLTreeNode<E>(e);
}
/**Insert an element and rebalance if necessary*/
@Override
public boolean insert(E e) {
boolean successful = super.insert(e);
if(!successful)
return false;
else {
balancePath(e); //Balance from e to the root if necessary
}
return true;
}
/**Update the height of a specified node*/
private void updateHeight(AVLTreeNode<E> node) {
if(node.left == null && node.right == null) //node is a leaf
node.height = 0;
else if(node.left == null) {
node.height = 1 + ((AVLTreeNode<E>)(node.right)).height;
}
else if(node.right == null) {
node.height = 1 + ((AVLTreeNode<E>)(node.left)).height;
}
else {
node.height = 1 + Math.max(((AVLTreeNode<E>)(node.left)).height,((AVLTreeNode<E>)(node.right)).height);
}
}
/**Balance the nodes in the path from the specified
* node to the root if necessary
*/
private void balancePath(E e) {
ArrayList<TreeNode<E>> path = path(e);
for(int i = path.size() - 1; i >= 0; i--) {
AVLTreeNode<E> A = (AVLTreeNode<E>)path.get(i);
updateHeight(A);
AVLTreeNode<E> parentOfA = (A == root) ? null : (AVLTreeNode<E>)(path.get(i - 1));
switch (balanceFactor(A)) {
case -2:
if(balanceFactor((AVLTreeNode<E>)A.left) <= 0) {
balanceLL(A, parentOfA);
}else {
balanceLR(A, parentOfA);
}
break;
case 2:
if(balanceFactor((AVLTreeNode<E>)A.right) >= 0){
balanceRR(A, parentOfA);
}else {
balanceRL(A, parentOfA);
}
default:
break;
}
}
}
/**Return the balance factor of the node*/
private int balanceFactor(AVLTreeNode<E> node) {
if(node.right == null) {
return -node.height;
}
else if(node.left == null) {
return + node.height;
}
else
return ((AVLTreeNode<E>)node.right).height -
((AVLTreeNode<E>)node.left).height;
}
/**LL旋转维持平衡*/
private void balanceLL(TreeNode<E> A,TreeNode<E> parentOfA) {
TreeNode<E> B = A.left;
if(A == root) {
root = B;
}
else {
if(parentOfA.left == A) {
parentOfA.left = B;
}else {
parentOfA.right = B;
}
}
A.left = B.right; //Make T2 the left subtree of A
B.right = A; //Make A the left child of B
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
}
/**LR旋转维持平衡*/
private void balanceLR(TreeNode<E> A,TreeNode<E> parentOfA) {
TreeNode<E> B = A.left; //A is left-heavy(左偏重)
TreeNode<E> C = B.right; //B is right-heavy
if(A == root) {
root = C;
}
else {
if(parentOfA.left == A) {
parentOfA.left = C;
}else {
parentOfA.right = C;
}
}
A.left = C.right; //Make T3 the left subtree of A
B.right = C.left; //Make T2 the right subtree of B
C.left = B;
C.right = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}
/**RR旋转维持平衡*/
private void balanceRR(TreeNode<E> A,TreeNode<E> parentOfA) {
TreeNode<E> B = A.right;
if(A == root) {
root = B;
}else {
if(parentOfA.left == A) {
parentOfA.left = B;
}
else {
parentOfA.right = B;
}
}
A.right = B.left;
B.left = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
}
/**RL旋转维持平衡*/
private void balanceRL(TreeNode<E> A,TreeNode<E> parentOfA) {
TreeNode<E> B = A.right;
TreeNode<E> C = B.left;
if(A == root) {
root = C;
}else {
if(parentOfA.left == A) {
parentOfA.left = C;
}else {
parentOfA.right = C;
}
}
A.right = C.left; //Make T2 the right subtree of A
B.left = C.right; //Make T3 the left subtree of B
C.left = A;
C.right = B;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}
/**Delete an element from the AVL tree*/
@Override
public boolean delete(E element) {
if(root == null) {
return false; //Element is not in the tree
}
//Locate the node to be deleted and alse locate its parent node
TreeNode<E> parent = null;
TreeNode<E> current = root;
while(current != null) {
if(element.compareTo(current.element) < 0) {
parent = current;
current = current.left;
}
else if(element.compareTo(current.element) > 0){
parent = current;
current =current.right;
}else
break;
}
if(current == null)
return false;
//Case 1 : current has no left children
if(current.left == null) {
//父结点连接当前删除结点的右结点
if(parent == null) {
root = current.right;
}else {
if(element.compareTo(parent.element) < 0)
parent.left = current.right;
else
parent.right = current.right;
}
//Balance the tree if necessary
balancePath(parent.element);
}
else {//Case 2: 定位当前删除结点的左子树的最大值(rightmost)以及其父结点,用rightmost替换删除结点值,同时删除rightmost
TreeNode<E> parentOfRightMost = current;
TreeNode<E> rightmost = current.left;
while(rightmost.right != null) {
parentOfRightMost = rightmost;
rightmost = rightmost.right;
}
//Replace the element in current by the element in rightmost
current.element = rightmost.element;
if(parentOfRightMost.right == rightmost)
parentOfRightMost.right = rightmost.left;
else //Special case : parentRightMost == current , 必须考虑这种情况
parentOfRightMost.left = rightmost.left;
//Balance the tree if necessary
balancePath(parentOfRightMost.element);
}
size--;
return true;
}
/**定义AVLTreeNode结点*/
protected static class AVLTreeNode<E extends Comparable<E>> extends BST.TreeNode<E>{
protected int height = 0;
public AVLTreeNode(E e) {
super(e);
}
}
}
测试分析:
package binary;
public class TestAVLTree {
public static void main(String[] args) {
AVLTree<Integer> tree = new AVLTree<>(new Integer[] {
25,20,5
});
System.out.println("After inserting 25 20 5:");
printTree(tree);
tree.insert(34);
tree.insert(50);
System.out.println("\nAfter inserting 34,50:");
printTree(tree);
tree.insert(30);
System.out.println("\nAfter inserting 30:");
printTree(tree);
tree.insert(10);
System.out.println("\nAfter inserting 10:");
printTree(tree);
tree.delete(34);
tree.delete(30);
tree.delete(50);
System.out.println("\nAfter removing 34,30,50:");
printTree(tree);
tree.delete(5);
System.out.println("\nAfter removing 5:");
printTree(tree);
System.out.println("\nTraverse the elements in the tree:");
for (int e : tree) {
System.out.print(e + " ");
}
}
public static void printTree(BST tree) {
System.out.print("Inorder:(Sorted) " );
tree.inorder();
System.out.print("\nPostorder: ");
tree.postorder();
System.out.print("\nPreorder: ");
tree.preorder();
System.out.print("\nThe number of nodes is " + tree.getSize());
System.out.println();
}
}
/**
After inserting 25 20 5:
Inorder:(Sorted) 5 20 25
Postorder: 5 25 20
Preorder: 20 5 25
The number of nodes is 3
After inserting 34,50:
Inorder:(Sorted) 5 20 25 34 50
Postorder: 5 25 50 34 20
Preorder: 20 5 34 25 50
The number of nodes is 5
After inserting 30:
Inorder:(Sorted) 5 20 25 30 34 50
Postorder: 5 20 30 50 34 25
Preorder: 25 20 5 34 30 50
The number of nodes is 6
After inserting 10:
Inorder:(Sorted) 5 10 20 25 30 34 50
Postorder: 5 20 10 30 50 34 25
Preorder: 25 10 5 20 34 30 50
The number of nodes is 7
After removing 34,30,50:
Inorder:(Sorted) 5 10 20 25
Postorder: 5 20 25 10
Preorder: 10 5 25 20
The number of nodes is 4
After removing 5:
Inorder:(Sorted) 10 20 25
Postorder: 10 25 20
Preorder: 20 10 25
The number of nodes is 3
Traverse the elements in the tree:
10 20 25
*/