390 likes | 429 Vues
AVL Tree. 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.44log(N+2)-.328
E N D
isa 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 anAVL tree is log N • The exact figure is1.44log(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.
1 1 1 1 AVL Non-AVL
0 1 1 Inserting a new node here destroys AVL. Various functions • All functions are O(log(N)), except insert and remove -> these may destroy the properties of AVL.
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.
Solve by single rotation Solve by double rotation • The 4 types:
Pull up a b Move the attachment place to the problem node. a b Z X X Y Y Z If it is fixed now, no further rotation is needed. Single rotation afterinsert
5 This node loses AVL property. 5 2 8 2 7 0 1 1 4 7 1 4 6 8 1 3 6 3 example1
3 3 3 rotate 2 2 2 1 1 3 Example 2 • Starting from nothing, weinsert 3,2,1 losesAVL To be continued
2 losesAVL 2 1 3 1 3 4 2 4 5 1 4 3 5 To be continued Then weinsert 4,5
losesAVL rotate 4 2 5 2 1 3 1 6 4 6 3 5 • Then weinsert 6 To be continued
losesAVL 4 4 2 rotate 5 2 6 1 3 1 3 6 5 7 7 Then weinsert 7
a b b a Z X Y X Y Z Double rotation • When Single rotation is useless Y does not change level
Loses AVL a a b b Z Z X Y c X Insertion takes place. There must be something in. Y1 Y2
a a c b Z Z c b X Y2 X Y1 Y2 Y1 The first rotation
a c c b a Z b X Y2 Y1 Y2 Z X Y1 the second rotation
It is like lettingc releaseY1,Y2 and carry a and b instead. c a a b b Z c X X Z Y1 Y2 Y1 Y2 Y1, Y2find places to attach • We do not know whether Y1 or Y2 is the cause. But it does not matter because in the end both of them reduce in level.
4 4 2 6 2 Loses AVL 6 rotate 1 3 5 7 1 3 5 15 16 7 16 15 example • Insert 16,15: losesAVL when inserting 15
Loses AVL 4 4 2 rotate 6 2 7 1 3 5 1 15 3 6 15 7 16 5 14 16 Must jump 14 • Insert 14
Two right moves:single rotation 4 7 2 7 4 15 1 3 rotate 6 15 2 6 14 16 5 14 16 1 3 5 13 13 Loses AVL • Insert 13
7 4 15 2 6 14 16 1 3 5 13 7 4 • Insert 12: this is an obvious single rotation Loses AVL 15 rotate 2 6 13 16 1 3 5 12 14 12
7 Loses AVL 7 4 4 • Insert 11: another single rotation 13 15 rotate 15 12 2 6 6 13 2 16 1 3 1 14 16 5 3 5 12 14 11 11
7 4 13 Loses AVL rotate 15 12 6 2 1 14 16 5 3 11 10 7 4 • Insert 10: another single rotation 13 15 6 11 2 14 16 5 3 1 10 12
7 4 13 • Insert 8 • Insert 9: simple double rotation 6 Loses AVL 15 2 11 5 3 1 10 12 14 16 8 9 10 8 9
class AvlNode • { • // Constructors • AvlNode( Comparable theElement ) • { • this( theElement, null, null ); • } • AvlNode( Comparable theElement, AvlNode lt, AvlNode rt ) • { • element = theElement; • left = lt; • right = rt; • height = 0; • } • // Friendly data; accessible by other package routines • Comparable element; // The data in the node • AvlNode left; // Left child • AvlNode right; // Right child • int height; // Height • } There will be a method that returnsheight. So we do not have to worry if the node we are looking at is null.
public class AvlTree • { private AvlNode root; • /** • * Construct the tree. • */ • public AvlTree( ) • { • root = null; • } • /** • * Insert into the tree; duplicates are ignored. • * @param x the item to insert. • */ • public void insert( Comparable x ) • { • root = insert( x, root ); • }
Same as binary search Tree • /** • * Find the smallest item in the tree. • * @return smallest item or null if empty. • */ • public Comparable findMin( ) • { • return elementAt( findMin( root ) ); • } • /** • * Find the largest item in the tree. • * @return the largest item of null if empty. • */ • public Comparable findMax( ) • { • return elementAt( findMax( root ) ); • }
/** • * Return the height of node t, or -1, if null. • */ • private static int height( AvlNode t ) • { • return t == null ? -1 : t.height; • } • /** • * Return maximum of lhs and rhs. • */ • private static int max( int lhs, int rhs ) • { • return lhs > rhs ? lhs : rhs; • } Helper functions
t Insert • /** • * Internal method to insert into a subtree. • * @param x the item to insert. • * @param t the node that roots the tree. • * @return the new root. • */ • private AvlNode insert( Comparable x, AvlNode t ) • { • if( t == null ) • t = new AvlNode( x, null, null ); • else if( x.compareTo( t.element ) < 0 ) • { • t.left = insert( x, t.left ); • if( height( t.left ) - height( t.right ) == 2 ) • if( x.compareTo( t.left.element ) < 0 ) • t = rotateWithLeftChild( t ); • else • t = doubleWithLeftChild( t ); • } If = =2 is true, x is below.
t • else if( x.compareTo( t.element ) > 0 ) • { • t.right = insert( x, t.right ); • if( height( t.right ) - height( t.left ) == 2 ) • if( x.compareTo( t.right.element ) > 0 ) • t = rotateWithRightChild( t ); • else • t = doubleWithRightChild( t ); • } • else • ; // Duplicate; do nothing • t.height = max( height( t.left ), height( t.right ) ) + 1; • return t; • }
k2 k1 k1 k2 • /** • * Rotate binary tree node with left child. • * For AVL trees, this is a single rotation for case 1. • * Update heights, then return new root. • */ • private static AvlNode rotateWithLeftChild( AvlNode k2 ) • { • AvlNode k1 = k2.left; • k2.left = k1.right; • k1.right = k2; • k2.height = max( height( k2.left ), height( k2.right ) ) + 1; • k1.height = max( height( k1.left ), k2.height ) + 1; • return k1; • }
k1 k2 k2 k1 • /** • * 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 AvlNode rotateWithRightChild( AvlNode k1 ) • { • AvlNode k2 = k1.right; • k1.right = k2.left; • k2.left = k1; • k1.height = max( height( k1.left ), height( k1.right ) ) + 1; • k2.height = max( height( k2.right ), k1.height ) + 1; • return k2; • }
k3 k3 k1 k2 Z k2 Z k2 k1 k3 X k1 Y2 X Z Y1 Y2 X Y1 Y2 Y1 • /** • * Double rotate binary tree node: first left child • * with its right child; then node k3 with new left child. • * For AVL trees, this is a double rotation for case 2. • * Update heights, then return new root. • */ • private static AvlNode doubleWithLeftChild( AvlNode k3 ) • { • k3.left = rotateWithRightChild( k3.left ); • return rotateWithLeftChild( k3 ); • }
k1 k1 k2 k3 Z k2 Z k1 k3 k2 X k3 Y2 X Y1 Z Y2 Y2 Y1 X Y1 • /** • * Double rotate binary tree node: first right child • * with its left child; then node k1 with new right child. • * For AVL trees, this is a double rotation for case 3. • * Update heights, then return new root. • */ • private static AvlNode doubleWithRightChild( AvlNode k1 ) • { • k1.right = rotateWithLeftChild( k1.right ); • return rotateWithRightChild( k1 ); • }
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.
Loses AVL Loses AVL
private AVLNode basicRemove( Comparable x, AVLNode t ) { if( t == null ) return t; // Item not found; do nothing if( x.compareTo( t.element ) < 0 ) t.left = basicRemove( x, t.left ); else if( x.compareTo( t.element ) > 0 ) t.right = basicRemove( x, t.right ); else if( t.left != null && t.right != null ) // Two children { t.element = findMin( t.right ).element; t.right = basicRemove( t.element, t.right ); } else t = ( t.left != null ) ? t.left : t.right; t.setHeight(); return t; } This is the same as BinaryNode’s remove()
private AVLNode remove(Comparable x, AVLNode r){ r = basicRemove(x,r); r = rebalance(r); return r; } public void remove(Comparable x){ root = remove(x, root); } private void setHeight(){// 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); }
private AVLNode rebalance(AVLNode r){ if (r == null) return r; int balance = balanceValue(r); if (balance == 2){//left hand side has more nodes than it should have if (balanceValue(r.left) ==-1) r.left = rotateWithRightChild(r.left); r = rotateWithLeftChild(r); } else if (balance == -2){//right hand side has more nodes than it should have if (balanceValue(r.right) ==1) r.right = rotateWithLeftChild(r.right); r = rotateWithRightChild(r); } r.setHeight(); return r; } public int balanceValue(AvlNode t){ return height(t.left) – height(t.right); }