Professional Documents
Culture Documents
7 Trees3
7 Trees3
7 Trees3
• h = O(log N)
3
IMPLEMENTING AVL TREES
• The private data needs another field to
keep the height of the node.
4
IMPLEMENTING AVL TREES
• The find, findMin and findMax operations
are just like in BinarySearchTrees
• The makeEmpty, operator=, printTree
etc., are all same.
5
INSERTING TO AN AVL TREE
Suppose we insert 6 to the AVL tree.
5
Height difference (balance factor) is 2
2
2 5
8 -1 (right subtree is empty)
1 4 7 1
3 6 0
6
INSERTING TO AN AVL TREE
Suppose we insert 6 to the previous AVL tree.
1 4 7 1
3 6 0
7
INSERTING TO AN AVL TREE
Suppose we insert 6 to the previous AVL tree.
3 Now this is
5 5 balanced.
2 2 1
2 5
8 2 7
Rotate around 7
1 4 7 1 1 4 6 8 0
0
3 6 0 3
8
INSERTING TO AN AVL TREE
• Just insert like a normal BST insert
9
INSERTING TO AN AVL TREE
• Let’s define the balance factor as the
difference between the heights of left and
right subtrees.
• Some nodes may become unbalanced, that is
have their balance factors become 2 (from 1)
or –2 (from –1).
• Only the balance factors of the nodes on the
path from the root to the newly inserted node
may change.
10
INSERTING TO AN AVL TREE
• Just insert like a normal BST insert
• Only nodes on the path from the inserted
node to the root may have their subtrees
altered 5
2
2 85
1 4 7 1
3 6 0
11
INSERTING TO AN AVL TREE
• Just insert like a normal BST insert
• Only nodes on the path from the inserted
node to the root may have their subtrees
altered 5
inserted node up 2 85
2 85
1 4 7 1
3 6 0
13
INSERTING TO AN AVL TREE
• Let us call the node that must be rebalanced
as a
• Since a has at most two children and a height
imbalance requires that a’s two subtrees’
heights differ by two, there are four cases to
consider:
14
IMBALANCE CASE 1
a k2
h+2 (was h+1)
h+1
(was h)
k1
h-1
h-1 Z
h
(was Y
h-1) X
15
IMBALANCE CASE 1
h+2 (was h+1)
a k2 k1 h+1
Single Rotation
h+1
(was h)
k1 h
k2 h
h-1
h
h-1 Z h-1
(was h-1) h-1
Y X Y Z
X
16
IMBALANCE CASE 1 EXAMPLE
5 5
2 5
8 k2 2 7 k1
8
1 4 7
k1 1 4 6 k2
3 6 3
17
IMBALANCE CASE 2
k1 a
k2
k2 k1
Y X Y Z
1 k1
3
4 k2
20
IMBALANCE CASE 2 EXAMPLE
2 2
1 k1
3 1 4 k2
4 k2 k1 3 5
21
IMBALANCE CASE 3
a k2
k1
X Y
22
IMBALANCE CASE 3
a k2 k1
k1 k2
Z X
X Y Y Z
k1
Z
X Y k2
D
B C
k1 k1 k3
k2
D
A B C D
A
B C
25
IMBALANCE CASE 3 EXAMPLE
a k3 14
3 17
k1
1 5 19
k2
D
0 2 4 7
B C 8
26
IMBALANCE CASE 3 EXAMPLE
k2 5
3
14
k1 k3
1 4 7 17
19
14 0 2 8
A B C D
3 17
1 5
19
0 2 4 7
8 27
INBALANCE CASE 4
k1 a Double Rotation k2
k1 k3
k3
k2
A
A B C D
D
B C
28
Single Rotation vs. Double Rotation
• Single rotation if insertion occurs on
the “outside”
• An insertion into the left subtree of
the left child of a (Case 1)
• An insertion into the right subtree
of the right child of a (Case 2)
29
Single Rotation vs. Double Rotation
• Double rotation if insertion occurs on
the “inside”
• An insertion into the right subtree
of the left child of a (Case 3)
• An insertion into the left subtree of
the right child of a (Case 4)
30
IMPLEMENTING AVL TREES
template <class Comparable>
class AvlTree;
void makeEmpty( );
void insert( const Comparable & x );
void remove( const Comparable & x );
// Avl manipulations
int height( AvlNode<Comparable> *t ) const;
int max( int lhs, int rhs ) const;
void rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const;
void rotateWithRightChild( AvlNode<Comparable> * & k1 ) const;
void doubleWithLeftChild( AvlNode<Comparable> * & k3 ) const;
void doubleWithRightChild( AvlNode<Comparable> * & k1 ) const;
}; 33
COMPUTING THE HEIGHT
/**
* Return the height of node t, or -1, if NULL.
*/
template <class Comparable>
int AvlTree<Comparable>::height( AvlNode<Comparable> *t )
const
{
if (t == NULL)
return -1;
return t->height;
}
34
(private) max
/**
* Return maximum of lhs and rhs.
*/
template <class Comparable>
int AvlTree<Comparable>::max( int lhs, int rhs )
const
{
if (lhs > rhs)
return lhs;
return rhs;
}
35
(private) INSERT
template <class Comparable>
void AvlTree<Comparable>::insert
( const Comparable & x, AvlNode<Comparable> * & t ) const
{
if ( t == NULL )
t = new AvlNode<Comparable>( x, NULL, NULL );
// Check if the left tree is out of balance (left subtree grew in height!)
if ( height( t->left ) - height( t->right ) == 2 )
if ( x < t->left->element ) // X was inserted to the left-left subtree!
rotateWithLeftChild( t );
else // X was inserted to the left-right subtree!
doubleWithLeftChild( t );
}
36
(private) INSERT
else if( t->element < x )
{ // Otherwise X is inserted to the right subtree
insert( x, t->right );
if ( height( t->right ) - height( t->left ) == 2 )
// height of the right subtree increased
if ( t->right->element < x )
// X was inserted to right-right subtree
rotateWithRightChild( t );
else // X was inserted to right-left subtree
doubleWithRightChild( t );
}
else
; // Duplicate; do nothing
h+1(was h) k1
h-1
h-1
Z
h (was h-1)
Y
X
39
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>::
rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
}
k1 k2 h+2 (was h+1)
h+1
(was h)
h-1
h-1
Z
h
(was h-1) Y
X
40
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>::
rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
} k2 h+2 (was h+1)
k1
h+1
(was h)
h-1
h-1
Z
h
(was h-1) Y
X
41
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>::
rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
} k2 h+2 (was h+1)
k1
h+1
(was h)
h-1
h-1
Z
h
(was h-1) Y
X
42
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>::rotateWithLeftChild ( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
}
k2 h
k1
h+1
(was h)
h-1
h-1
Z
h
(was h-1) Y
X
43
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>:: rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
}
k2 h
k1
h+1
h-1
h-1
Z
h
(was h-1) Y
X
44
ROTATIONS-rotateWithLeftChild
void AvlTree<Comparable>::rotateWithLeftChild( AvlNode<Comparable> * & k2 ) const
{
AvlNode<Comparable> *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;
k2 = k1;
} k2 h
h+1
h-1
h-1
Z
h
(was h-1) Y
X
45
ROTATIONS-rotateWithRightChild
/**
* Rotate binary tree node with right child.
* For AVL trees, this is a single rotation for case 4.
* Update heights, then set new root.
*/
template <class Comparable>
void AvlTree<Comparable>::rotateWithRightChild
( AvlNode<Comparable> * & k1 ) const
{
AvlNode<Comparable> *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;
k1 = k2;
}
46
ROTATIONS-DoubleWithLeftChild
/**
* 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 set new root.
*/
template <class Comparable>
void AvlTree<Comparable>::doubleWithLeftChild
( AvlNode<Comparable> * & k3 ) const
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
47
ROTATIONS-DoubleWithLeftChild
template <class Comparable>
void AvlTree<Comparable>::doubleWithLeftChild( AvlNode<Comparable> * & k3 )
const
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
k3
k1
k2
D
B C
48
ROTATIONS-DoubleWithLeftChild
template <class Comparable>
void AvlTree<Comparable>::doubleWithLeftChild( AvlNode<Comparable> * & k3 )
const
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
k3
k2
k1
D
A B C
49
ROTATIONS-DoubleWithLeftChild
template <class Comparable>
void AvlTree<Comparable>::doubleWithLeftChild
( AvlNode<Comparable> * & k3 ) const
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 ); k3
}
k2
k1
D
A B C
50
ROTATIONS-DoubleWithLeftChild
template <class Comparable>
void AvlTree<Comparable>::doubleWithLeftChild
( AvlNode<Comparable> * & k3 ) const
{
rotateWithRightChild( k3->left );
rotateWithLeftChild( k3 );
}
k2
k1 k3
A B C D
51
ROTATIONS-DoubleWithRightChild
/**
* 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 set new root.
*/
template <class Comparable>
void AvlTree<Comparable>::doubleWithRightChild
( AvlNode<Comparable> * & k1 ) const
{
rotateWithLeftChild( k1->right );
rotateWithRightChild( k1 );
}
52
DELETIONS FROM AN AVL TREE
• Proceed as in the case of a deletion from a
BST.
– node is leaf ⇒ just delete it from the parent
– node has single child ⇒ connect child to the
grantparent node
– two children ⇒ replace with largest child from left
or smallest from right (and delete that grandchild
(which has at most 1 child)
53
DELETIONS FROM AN AVL TREE
• The deletions will upset the balance factors of
some of the remaining nodes.
• So they will have to be re-balanced.
54
DELETION CASE 1
Before deletion
h+3
k1
h+2
k2
h+1
h+1
X Y h or h+1
Heights of subtrees
55
DELETION CASE 1
h+3 h+3
Out of balance
k1 k1
h+2 h+2
k2 h+1 k2 h
Z
Z
h+1
X Y h or h+1 X Y h or h+1
56
DELETION CASE 1
h+3
h+2 or h+3
Out of balance k2
k1
Rotation
h+1 or h+2
h+2
k2 h k1
Z
h+1
h or h+1 h
h+1 X
Z
X Y h or h+1
Y
57
DELETION CASE 1
Now Since the height of this
Before h+3 subtree changed, the balance of its
h+2 or h+3 parent may have changed.
k2
58
DELETION CASE 1
Now The height of this subtree
Before h+3 did NOT change, so
h+2 or h+3 the balance of
k2 its parent will not change
No further action
h+1 or h+2
is necessary
k1
h+1
h or h+1
h
X
Z
59
DELETION CASE 1
• Symmetric cases are handled in a similar way
60
DELETION CASE 2
h+3 • After deletion from Z, it
k1
now has height h.
• X also has height h.
h+2 • Node k1 now has an
k2 imbalance.
h
h+1
Z
h k3
h h-1
or or
h-1 Y Y’ h
’
(at least ’ height h)
1 side has 61
DELETION CASE 2
h+2
h+3
k3
k1
Double Rotation
h+1
h+2
k2 k1 h+1
k2 h
h+1
Z h h h
h h-1
k3 or
h-1 or
X Y’ h Z
X Y
’ ’
h h-1
or or (at least 1 side has height h)
Y Y’ h
h-1
’ ’
(at least 1 side has height h)
62
DELETION CASE 2
• Now the height of the h+2
63
META-SUMMARY
Find Insert Remove
Average Worst Average Worst Average Worst
Case Case Case Case Case Case
Binary
Search O(log N) O(N) O(log N) O(N) O(logN) O(N)
Trees
AVL
O(log N) O(logN) O(log N) O(log N) O(log N) O(log N)
Search
Trees 64
ROAD MAP FROM HERE ON
• Hashing
– insert/delete/find almost O(1)
– lots of wasted space
• Heaps and priority queues
– More interesting tree structures
• Sorting Algorithms
• Disjoint Sets
• Graphs and Graph Algorithms
65