AVL Trees
AVL Trees
Binary search trees with a large height/depth are inefficient.
4 6
3 7
2 8
1 9
An AVL (Adelson-Velskii and Landis) tree is a binary search tree with a
balance condition.
The balance condition must be easy to maintain, and it ensures that the
depth of the tree is O(log n).
An AVL tree is identical to a binary search tree, except that for every node
in the tree, the height of the left and right subtrees can differ by at most 1.
The height of an empty tree is defined to be -1.
The height of the left subtree minus the height of the right subtree of a node
is called the balance of the node.
For an AVL tree, the balances of the nodes are always -1, 0 or 1.
AVL - Trees
7
5
2 8
2 8
7 1 4
1 4
3 5
3
An AVL Tree Not an AVL Tree
AVL Trees
5
2 8
7
1 4
6
3
When we do an insertion, we need to update all the balancing
information for the nodes on the path back to the root
but the reason that insertion is potentially difficult is that inserting a
node could violate the AVL tree property.
For instance, inserting 6 into the AVL tree in figure would destroy
the balance condition at the node with key 8.
If this is the case, then the property has to be restored before the
insertion step is considered over.
It turns out that this can always be done with a simple modification to
the tree, known as a rotation.
AVL Trees
After the insertion/rotation operations, the
following properties of the AVL tree must
be restored
(a) the inorder traversal of the transformed
tree is the same as for the original tree (i.e.,
the new tree remains a binary search tree)
(b) the tree after the insertion/rotation is
height balanced.
AVL Trees
After an insertion, only nodes that are on
the path from the insertion point to the root
might have their balance altered
Follow the path up to the root, find the first
node (i.e., deepest) whose new balance
violates the AVL condition.
Call this node α
Rebalance the tree at node α
This guarantees that the entire tree is
balanced.
AVL Trees
Violation may occur when an insertion into
1. left subtree of left child of α (LL case)
2. right subtree of left child of α (LR case)
3. left subtree of right child of α (RL case)
4. right subtree of right child of α (RR
case)
AVL Trees
Violation may occur when an insertion into
1. left subtree of left child of α (LL case)
α
4. right subtree of right child of α (RR case)
α
X
AVL Trees
Violation may occur when an insertion into
2. right subtree of left child of α (LR case)
α
3. left subtree of right child of a α (RL case)
α
X
X
AVL Trees
Rotation
to restore the AVL tree after
insertion
Single rotation
for case 1 and 4
Double rotation
for case 2 and 3
AVL Trees
Single Rotation for case 1
k2 k2
k1 kk11
Z Z
k2
Y Y
X X
Y Z
Single Rotation for case 4
k1 k1
k2 k22
X X
k1
Y Y
Z Z
X Y
AVL Trees: Single Rotation
Example: 3 2 1 4 5 6 7
construct AVL Tree
321
3
3
2
2
1
1
AVL Trees: Single Rotation
Example: 3 2 1 4 5 6 7
construct AVL Tree
321
3
2
2
1 3
1
AVL Trees: Single Rotation
45
2
2
1 4
1 3
3 5
4
5
AVL Trees: Single Rotation
6
1 4 2
5 1 4
3
3 5
6
6
AVL Trees: Single Rotation
7
4
2 5
2 5
1 3 6
1 3 6
7
7
AVL Trees: Double Rotation
Single rotation fails to fix cases 2 and 3
i.e. LR and RL cases
AVL Trees: Double Rotation
Double rotation is used
case 2 (LR case)
Step1: Rotate k1 and k2
Step2: Rotate k2 and k3
AVL Trees: Double Rotation
Double rotation is used
case 2 (LR case)
k3 k3
k1 k1
k2 D k2 D
A A
B C B C
Step1: Rotate k1 and k2
AVL Trees: Double Rotation
Double rotation is used
Step 1: Single Rotation
k1 and k2 rotated
case 2 (LR case)
k3
k3
k1 k2
k2 D
k1 D
A C
B C
A B
LR LL
Step1: Rotate k1 and k2
AVL Trees: Double Rotation
Double rotation is used
Step 2: Single Rotation
k3 and k2 rotated
case 2 (LR case)
k3 k2
k1
k1 k3
k2 D
A
C A B C D
B
LR Balanced
Step2: Rotate k2 and k3
AVL Trees: Double Rotation
case 3 (RL case)
Step1: Rotate k2 and k3
Step2: Rotate k1 and k2
AVL Trees: Double Rotation
Example:
AVL Trees: Double Rotation
16 15
4 4
2 6 6
2
1 3 5 7 k1 k1
1 3 5 7
16 k3 16 k3
15 Double Rotation 15 k2
k2
Step 1: Rotate 15 and 16
AVL Trees: Double Rotation
16 15
4 4
2 6 6
2
1 3 5 7 k1 k1
1 3 5 7
16 k3 15 k2
15 Double Rotation k3 16
k2
Step 2: Rotate 7 and 15
AVL Trees: Double Rotation
Insert 14
Step1: Rotate k2 and k3
Step2: Rotate k1 and k2
AVL Trees: Double Rotation
Insert 13 (This is single rotation: RR Case)
AVL Trees: Double Rotation
Insert 12
AVL Trees: Double Rotation
Insert 11 and 10 (single rotation), then 8
AVL Trees: Double Rotation
Inserting 9
AVL Trees: Declaration
struct avl_node
{
element_type element;
avl_node *left;
avl_node * right;
int height;
};
avl_node * SEARCH_TREE;
AVL Trees: Height Calculation
int height(avl_node * p )
{
if( p == NULL )
return -1;
else
return p->height;
}
Insert operation for binary search
trees
tree_node* insert( int x, tree_node* T ) {
/*1*/ if( T == NULL ) { /* Create and return a one-node tree */
/*2*/ T = (SEARCH_TREE) malloc ( sizeof (struct tree_node) );
/*3*/ if( T == NULL )
/*4*/ printf("Out of space!!!");
else {
/*5*/ T->element = x;
/*6*/ T->left = T->right = NULL;
}
}
/*7*/ else if( x < T->element )
/*8*/ T->left = insert( x, T->left );
/*9*/ else if( x > T->element )
/*10*/ T->right = insert( x, T->right );
/* else x is in the tree already. We'll do nothing */
/*11*/ return T; /* Don't forget this line!! */
}
AVL Trees: Insert Operation
avl_node * insert( int x, avl_node * T) { else if( x > T->element ) {
if( T == NULL ) { /* Create and return a one-node tree */ T->right = insert( x, T->right);
T = (avl_node *) malloc ( sizeof (struct avl_node) );
if( ( height( T->right ) - height( T->left ) ) == 2
if( T == NULL )
if( x > T->right->element )
printf("Out of space!!!");
else { T = SingleRotateWithRight( T );
T->element = x; T->height = 0; else
T->left = T->right = NULL; T = DoubleRotateWithRight( T );
} }
}
/* Else x is in the tree already. We'll do nothing */
else if( x < T->element ) {
T->height = max( height(T->left), height(T->right) ) +
T->left = insert( x, T->left);
1;
if( ( height( T->left ) - height( T->right ) ) == 2
return T;
if( x < T->left->element )
T = SingleRotateWithLeft( T ); }
else
T = DoubleRotateWithLeft( T );
}
AVL Trees: Inserting 16
SEARCH_TREE = insert( 16, SEARCH_TREE)
16
avl_node*insert( int x, avl_node*T){
4 if( T == NULL ){
}
6 else if( x < T->element ) {
2
}
1 3 5 7 else if( x > T->element ) {
T->right = insert( x, T->right);
NULL
AVL Trees: Inserting 16
SEARCH_TREE = insert( 16, SEARCH_TREE)
16
4
2 6
else if( x > T->element ) {
T->right = insert( x, T->right);
1 3 5 7
avl_node*insert( int x, avl_node*T){
if( T == NULL ){
T = (avl_node *) malloc ( sizeof (struct avl_node) );
16
NULL if( T == NULL )
printf("Out of space!!!");
else {
T->element = x; T->height = 0;
T->left = T->right = NULL;
}
Recursion rolls back
AVL Trees: Inserting 16
SEARCH_TREE = insert( 16, SEARCH_TREE)
16
else if( x > T->element ) {
4
T->right = insert( x, T->right);
if( ( height( T->left ) - height( T->right ) ) == 2
{ /*condition is false here */
2 6
}
}
T->height = max( height(T->left), height(T->right) ) + 1;
1 3 5 7 return T;
}
16
AVL Trees: Inserting 15
SEARCH_TREE = insert( 15, SEARCH_TREE)
15
avl_node*insert( int x, avl_node*T){
4 if( T == NULL ){
}
6 else if( x < T->element ) {
2
}
1 3 5 7 else if( x > T->element ) {
T->right = insert( x, T->right);
16
else if( x < T->element ) {
T->left = insert( x, T->left);
NULL
AVL Trees: Inserting 15
SEARCH_TREE = insert( 16, SEARCH_TREE)
15
4 else if( x < T->element ) {
T->reft = insert( x, T->left);
6 avl_node*insert( int x, avl_node*T){
2 if( T == NULL ){
T = (avl_node *) malloc ( sizeof (struct avl_node) );
if( T == NULL )
1 3 5 7 printf("Out of space!!!");
else {
T->element = x; T->height = 0;
T->left = T->right = NULL;
16 }
…
15
NULL …
…
return T; Recursion rolls back
AVL Trees: Inserting 15
SEARCH_TREE = insert( 16, SEARCH_TREE)
15
4 else if( x > T->element ) {
T->right = insert( x, T->right);
}
2 6 avl_node*insert( int x, avl_node*T){
…
…
…
1 3 5 7 return T;
16
15
Recursion rolls back further
AVL Trees: Inserting 15
SEARCH_TREE = insert( 16, SEARCH_TREE)
15
4 else if( x > T->element ) {
T->right = insert( x, T->right);
if( ( height( T->right ) - height( T->left ) ) == 2
if( x > T->right->element )
2 6 T = SingleRotateWithRight( T );
else
T = DoubleRotateWithRight( T );
}
1 3 5 7 /* Else x is in the tree already. We'll do nothing */
T->height = max( height(T->left), height(T->right) ) + 1;
return T;
16}
• Now the subtree writh root 7 is ubalanced
15
perform double rotation with right
AVL Trees: SingleRotateWithLeft
/* This function can be called only if k2 has a left child. */
/* Perform a rotate between a node (k2) and its left child. */
/* Update heights. */
/* Then return new root. */
avl_node * SingleRotateWithLeft( avl_node * k2 ) {
avl_node * k1;
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; /* New root */
}
Single Rotation for case 1
k2 k1
k2->left
k1 k2
k1->right Z k2->left
X
Y Z
Y
X
AVL Trees: SingleRotateWithRight
/* This function can be called only if k1 has a right child. */
/* Perform a rotate between a node (k1) and its right child. */
/* Update heights. */
/* Then return new root. */
avl_node * SingleRotateWithRight( avl_node * k1 ) {
avl_node * k2;
k2 = k1->right;
k1->right = k2->left ;
k2->left = k1;
k1->height = max( height(k1->left), height(k1->right) ) + 1;
k2->height = max( k1->height, height(k2->right) ) + 1;
return k2; /* New root */
}
Single Rotation for case 4
k1
k1->right k2
k2 k1
X
k2->left k1->right
Y Z
X Y
Z
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k3->left = SingleRotateWithRight( k3->left );
k3
k3
k1 k2
k2 D
k1 D
A C
B C
A B
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k3->left = SingleRotateWithRight( k3->left );
/* rotate between k3 and k2 */
return(SingleRotateWithLeft( k3 ) );
}
k3
k3
k1 k2
k2 D
k1 D
A C
B C
A B
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k3->left = SingleRotateWithRight( k3->left );
/* rotate between k3 and k2 */
return(SingleRotateWithLeft( k3 ) );
}
k3 k2
k1
k1 k3
k2 D
A
C A B C D
B
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k1 = k3->left;
k2 = SingleRotateWithRight( k1);
k3->left = k2
}
k3
k3
k1 k2
k2 D
k1 D
A C
B C
A B
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k1 = k3->left;
k2 = SingleRotateWithRight( k1);
k3->left = k2
/* rotate between k3 and k2 */
k2 =SingleRotateWithLeft( k3 )
return(k2);
} k 3
k3
k1 k2
k2 D
k1 D
A C
B C
A B
AVL Trees: DoubleRotateWithLeft
/* This function can be called only if k3 has a left child */
/* and k3's left child has a right child */
/* Do the left-right double rotation. Update heights */
avl_node * DoubleRotateWithLeft( avl_node * k3 )
{
/* rotate between k1 and k2 */
k1 = k3->left;
k2 = SingleRotateWithRight( k1);
k3->left = k2
/* rotate between k3 and k2 */
k2 =SingleRotateWithLeft( k3 )
return(k2);
} k 3 k2
k1 k1 k3
k2 D
A A B C D
B C
AVL Trees: Double Rotation
4 4
2 6 2 6
1 3 5 7 k1 k1
1 3 5 7
16 k3 16 k3
15
k2 Double Rotation 15 k
2
Step 1: Rotate 15 and 16
avl_node * DoubleRotateWithRight( avl_node * k1 )
{
/* rotate between k3 (16) and k2 (15 )*/
k1->right = SingleRotateWithLeft( k1->right );
/* rotate between k1 (7) and k2 (15) */
return(SingleRotateWithRight( k1 ) );
}
AVL Trees: Double Rotation
4 4
2 6 2 6
1 3 5 7 k1 k1
1 3 5 7
16 k3 15 k2
15
k2 Double Rotation k3 16
Step 2: Rotate 7 and 15
avl_node * DoubleRotateWithRight( avl_node * k1 )
{
/* rotate between k3 (16) and k2 (15 )*/
k1->right = SingleRotateWithLeft( k1->right );
/* rotate between k1 (7) and k2 (15) */
return(SingleRotateWithRight( k1 ) );
}