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 */
文章来源: 模拟平衡二叉查找树底层实现(AVL)