AVL Tree 1 is a binary search tree
AVL Tree 1
is a binary search tree that • For each node: – The height of its left and right subtree can only differ at most 1. – If a tree is an empty tree, we let its height == -1. • The height of an AVL tree is log N – The exact figure is 1. 44 log(N+2)-. 328 • The height difference constraint leads to: – The minimal number of nodes for a tree of height h, s(h) = s(h-1)+s(h-2)+1 • When h=0, s(h) =1 • When h=1, s(h) =2 – This is similar to fibonacci. 2
1 1 AVL Non-AVL 3
Various functions • All functions are O(log(N)), except insert and remove -> these may destroy the properties of AVL. 1 1 0 Inserting a new node here destroys AVL. 4
Fix insert+ remove with rotation insert – Only nodes on the path from the insertion point to the root have a chance of height change. – If we follow up from the inserted node, we will eventually find the deepest node that loses its AVL property. We will fix such node. There can only be 4 types of such node. 5
• The 4 types: Solve by single rotation Solve by double rotation 6
Single rotation after insert Pull up a b Move the attachment place to the problem node. b a Z Y X Y Z X If it is fixed now, no further rotation is needed. 7
example 1 5 This node loses AVL property. 2 1 8 1 7 4 1 3 6 5 2 0 1 7 4 6 8 3 8
Example 2 • Starting from nothing, we insert 3, 2, 1 loses AVL 3 3 3 2 rotate 2 1 To be continued 3 9
2 Then we insert 4, 5 2 1 loses AVL 1 3 3 4 4 2 5 1 4 3 5 To be continued 10
• Then we insert 6 loses AVL 2 1 rotate 4 3 4 2 5 5 1 6 3 6 To be continued 11
Then we insert 7 loses AVL 4 2 1 rotate 5 3 4 2 1 6 6 3 5 7 7 12
Double rotation • When Single rotation is useless a b b a Z X X Y Y Z Y does not change level 13
Loses AVL a a b b Z c X Y Z X Insertion takes place. There must be something in. Y 1 Y 2 14
The first rotation a a c b c Z Z b Y 2 X Y 1 15
the second rotation a c c b Z b Y 2 X a X Y 1 Y 2 Z Y 1 16
It is like letting c release Y 1, Y 2 and carry a and b instead. c a b b c Z X X Y 1 Y 2 a Z Y 1 Y 2 Y 1, Y 2 find places to attach • We do not know whether Y 1 or Y 2 is the cause. But it does not matter because in the end both of them reduce in level. 17
example • Insert 16, 15: loses AVL when inserting 15 4 4 2 1 6 3 5 Loses AVL 7 6 rotate 1 16 15 2 3 5 15 7 16 18
• Insert 14 Loses AVL 4 2 1 rotate 6 3 5 7 2 1 15 16 4 7 3 6 5 15 14 16 Must jump 14 19
• Insert 13 Loses AVL Two right moves: single rotation 4 7 2 1 7 3 6 5 4 15 14 16 rotate 2 1 15 6 14 16 3 5 13 13 20
• Insert 12: this is an obvious single rotation 7 7 4 2 1 Loses AVL 6 14 16 3 5 13 4 15 rotate 2 1 15 6 13 16 3 5 12 14 12 21
• Insert 11: another single rotation 7 4 2 1 7 Loses AVL 4 15 6 13 16 3 5 12 14 rotate 2 1 13 6 3 5 11 15 12 14 11 22 16
• Insert 10: another single rotation 7 7 4 13 Loses AVL 2 1 4 15 6 12 3 5 11 14 rotate 16 2 1 13 6 11 15 3 5 10 12 14 16 10 23
• Insert 8 • Insert 9: simple double 7 rotation 4 6 2 1 13 3 Loses AVL 5 11 10 12 14 15 16 8 9 9 8 10 24
1. 2. 3. 4. 5. 6. 7. class Avl. Node { // Constructors Avl. Node( Comparable the. Element ) { this( the. Element, null ); } 8. 9. 10. 11. 12. 13. 14. Avl. Node( Comparable the. Element, Avl. Node lt, Avl. Node rt ) { element = the. Element; left = lt; right = rt; height = 0; } 15. 16. 17. 18. 19. 20. // Friendly data; accessible by other package routines Comparable element; // The data in the node Avl. Node left; // Left child Avl. Node right; // Right child int height; // Height } There will be a method that returns height. So we do not have to worry if the node we are looking at is null. 25
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. public class Avl. Tree { private Avl. Node root; /** * Construct the tree. */ public Avl. Tree( ) { root = null; } /** * Insert into the tree; duplicates are ignored. * @param x the item to insert. */ public void insert( Comparable x ) { root = insert( x, root ); } 26
18. /** 19. 20. 21. 22. 23. 24. 25. * Find the smallest item in the tree. * @return smallest item or null if empty. */ public Comparable find. Min( ) { return element. At( find. Min( root ) ); } 26. 27. 28. 29. 30. 31. 32. 33. /** * Find the largest item in the tree. * @return the largest item of null if empty. */ public Comparable find. Max( ) { return element. At( find. Max( root ) ); } Same as binary search Tree 27
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. **/ * Return the height of node t, or -1, if null. */ private static int height( Avl. Node t ) { return t == null ? -1 : t. height; } Helper functions /** * Return maximum of lhs and rhs. */ private static int max( int lhs, int rhs ) { return lhs > rhs ? lhs : rhs; } 28
**/ 2. * 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 1. Internal method to insert into a subtree. * @param x the item to insert. * @param t the node that roots the tree. Insert * @return the new root. */ private Avl. Node insert( Comparable x, Avl. Node t ) { if( t == null ) t t = new Avl. Node( x, null ); else if( x. compare. To( t. element ) < 0 ) { If = =2 is true, x is below. t. left = insert( x, t. left ); if( height( t. left ) - height( t. right ) == 2 ) if( x. compare. To( t. left. element ) < 0 ) t = rotate. With. Left. Child( t ); else t = double. With. Left. Child( t ); } 29
t 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. else if( x. compare. To( t. element ) > 0 ) { t. right = insert( x, t. right ); if( height( t. right ) - height( t. left ) == 2 ) if( x. compare. To( t. right. element ) > 0 ) t = rotate. With. Right. Child( t ); else t = double. With. Right. Child( t ); } else ; // Duplicate; do nothing t. height = max( height( t. left ), height( t. right ) ) + 1; return t; } 30
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. k 2 **/ * Rotate binary tree node with left child. k 1 * For AVL trees, this is a single rotation for case 1. * Update heights, then return new root. */ private static Avl. Node rotate. With. Left. Child( Avl. Node k 2 ) { Avl. Node k 1 = k 2. left; k 2. left = k 1. right; k 1. right = k 2; k 2. height = max( height( k 2. left ), height( k 2. right ) ) + 1; k 1. height = max( height( k 1. left ), k 2. height ) + 1; return k 1; k 1 } k 2 31
1. **/ 2. * 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Rotate binary tree node with right child. * For AVL trees, this is a single rotation for case 4. * Update heights, then return new root. */ private static Avl. Node rotate. With. Right. Child( Avl. Node k 1 ) { Avl. Node k 2 = k 1. right; k 1. right = k 2. left; k 2. left = k 1; k 1. height = max( height( k 1. left ), height( k 1. right ) ) + 1; k 2. height = max( height( k 2. right ), k 1. height ) + 1; return k 2; } k 1 k 2 k 1 32
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. /** * Double rotate binary tree node: first left child * with its right child; then node k 3 with new left child. * For AVL trees, this is a double rotation for case 2. * Update heights, then return new root. */ private static Avl. Node double. With. Left. Child( Avl. Node k 3 ) { k 3. left = rotate. With. Right. Child( k 3. left ); return rotate. With. Left. Child( k 3 ); } k 3 k 1 k 2 X Y 1 Y 2 k 3 Z k 2 k 1 Y 2 X Y 1 Z k 2 k 1 k 3 X Y 1 Y 2 Z 33
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. /** * Double rotate binary tree node: first right child * with its left child; then node k 1 with new right child. * For AVL trees, this is a double rotation for case 3. * Update heights, then return new root. */ private static Avl. Node double. With. Right. Child( Avl. Node k 1 ) { k 1. right = rotate. With. Left. Child( k 1. right ); return rotate. With. Right. Child( k 1 ); } k 1 Z k 1 k 3 k 2 Z X Y 2 Y 1 k 2 Y 2 k 1 k 3 Y 1 X k 3 Z Y 2 Y 1 X 34
Remove a node from AVL • First, do a normal remove • Then rebalance, starting from the node just above the removed node up to the root. • We need to rebalance every node because balancing a child can make its parent loses AVL. 35
Loses AVL 36
private AVLNode basic. Remove( Comparable x, AVLNode t ) { if( t == null ) return t; // Item not found; do nothing if( x. compare. To( t. element ) < 0 ) t. left = basic. Remove( x, t. left ); else if( x. compare. To( t. element ) > 0 ) t. right = basic. Remove( x, t. right ); else if( t. left != null && t. right != null ) // Two children { t. element = find. Min( t. right ). element; t. right = basic. Remove( t. element, t. right ); } else t = ( t. left != null ) ? t. left : t. right; t. set. Height(); return t; } This is the same as Binary. Node’s remove() 37
private AVLNode remove(Comparable x, AVLNode r){ r = basic. Remove(x, r); r = rebalance(r); return r; } public void remove(Comparable x){ root = remove(x, root); } private void set. Height(){// this is in AVLNode height = 1 + Math. max(height(left), height(right)); } private static int height(AVLNode n){ // this is in AVLNode return (n == null ? -1 : n. height); } 38
private AVLNode rebalance(AVLNode r){ if (r == null) return r; int balance = balance. Value(r); if (balance == 2){//left hand side has more nodes than it should have if (balance. Value(r. left) ==-1) r. left = rotate. With. Right. Child(r. left); r = rotate. With. Left. Child(r); } else if (balance == -2){//right hand side has more nodes than it should have if (balance. Value(r. right) ==1) r. right = rotate. With. Left. Child(r. right); r = rotate. With. Right. Child(r); } r. set. Height(); return r; } public int balance. Value(Avl. Node t){ return height(t. left) – height(t. right); } 39
- Slides: 39