Adelsion Velski and Lendis in 1962 introduced binary tree structure that is balanced with respect to height of subtrees.
AVL Trees
Adelsion
Velski and Lendis in 1962 introduced binary tree structure that is balanced
with respect to height of subtrees. The tree can be made balanced and because
of this retrieval of any node can be done in O(logn) times, where n is total
number of nodes. From the name of these scientists the tree is called AVL tree.
• Definition
An empty
tree is height balanced if T is a non empty binary tree with TL and
TR as its left and right subtrees. The T is height balanced if and
only if,
i) TL
and TR are height balanced.
ii) HL
- hR <=1 where hL - hR are heights of TL
and TR
The idea
of balancing a tree is obtained by calculating the balance factor of a tree.
• Definition of Balance Factor
The
balance factor BF(T) of a node in binary tree is defined to be hL -
hR where he hL and hR are heights of left and
right subtrees of T.
For any
node in AVL tree the balance factor i.e. BF(T) is -1, 0 or +1
• Height of AVL tree
Theorem: The height of AVL tree with
n elements (nodes) is O(logN).
Proof: Let an AVL tree with N
nodes in it. Nh be the minimum number of nodes in an AVL tree of height h.
In worst
case, one subtree may have height h-1 and other subtree may have height h−2. And both
these subtrees are AVL trees. Since for every node in AVL tree the height of
left and right subtrees differ by at most 1. Hence,
Nh
= Nh_1+Nh_2+1
Where Nh
denotes the minimum number of nodes in an AVL tree of height h.
N0=0 N1 =2
We can
also write it as
N> Nh
= Nh−2
+ Nh_2+1
> 2Nh-2
> 4Nh-4
.
.
.
> 2i Nh-2i
If value
of h is even, let i = h/2-1
Then
equation becomes,
N > 2h/2-1
N2
= N >
2h/2-1x4 N2 =4
= O (log
N)
If value
of h is odd, let i= (h-1)/2 then equation becomes.
N > 2(h-1)/2Nı
= N >
2(h-1)/2x1 N1 =1
h=O(log
N)
This
proves that height of AVL tree is always O(log N). Hence search, insertion and
deletion can be carried out in logarithmic time.
Theorem : The height of AVL tree h
with minimum number of nodes n is 1.44 log n.
Proof ; Let Fh be the AVL
tree with height h having minimum number of nodes. The tree can be shown as
below.
Hence
minimum number of nodes in AVL tree is = Length of left subtree + Length of
right subtree + 1
|Fh|
= |Fh-1| + | Fh-2| + 1
Also
|F0|=1
and |F1| = 2
This
denotes the Fibonacci tree.
Adding 1
to both sides.
|Fh|+1=(|Fh-1|+1)+(|Fh-2|+1).
Thus the
numbers | Fh|+1 are Fibonacci numbers. Using approximate formula for
Fibonacci numbers, we will ge tan approximate value as :
|Fh|+1=1/√5 (1+√5/2) h+3
Taking
logarithm
=h≈ 1.44 log
| Fh |
Hence
the worst case height of an AVL tree with n nodes is 1.44 log n.
The
Fibonacci trees are as shown below.
Difference between AVL tree and binary search
tree
•The AVL
tree follows the property of binary search tree. In fact AVL trees are
basically binary search trees with balance factor as -1, 0 or + 1.
•After
insertion of any node in an AVL tree if the balance factor of any node becomes
other than -1, 0, or + 1 then it is said that AVL property is violated. Then we
have to restore the destroyed balance condition. The balance factor is denoted
at right top corner inside the node.
For example:
• After
an insertion of a new node if balance condition gets destroyed, then the nodes
on that path (new node insertion point to root) needs to be readjusted. That
means only the affected subtree is to be rebalanced.
• The
rebalancing should be such that entire tree should satisfy AVL property.
In above
given example -
There
are four different cases when rebalancing is required after insertion of new
node.
1. An
insertion of new node into left subtree of left child (LL).
2. An
insertion of new node into right subtree of left child (LR).
3. An
insertion of new node into left subtree of right child (RL).
4. An
insertion of new node into right subtree of right child (RR).
There is
a symmetry between case 1 and 4. Similarly symmetry exists between case 2 and 3.
Some
modifications done on AVL tree in order to rebalance it is called rotations of
AVL tree.
There
are two types of rotations.
Single
rotation
Double
rotation
Insertion algorithm
1.
Insert a new node as new leaf just as in ordinary binary search tree.
2. Now
trace the path from insertion point (new node inserted as leaf) towards root.
For each node 'n' encountered, check if heights of left (n) and right (n)
differ by at most 1.
a) If
yes, move towards parent (n).
b)
Otherwise restructure by doing either a single rotation or a double rotation.
Thus
once we perform a rotation at node 'n' we do not require to perform any
rotation at any ancestor on 'n'.
Different rotations in AVL tree
1. LL rotation
When
node '1' gets inserted as a left child of node 'C' then AVL property gets
destroyed i.e. node A has balance factor + 2.
The LL
rotation has to be applied to rebalance the nodes.
2. RR rotation
When
node '4' gets attached as right child of node 'C' then node 'A' gets unbalanced. The rotation which needs to be
applied is RR rotation as shown in Fig. 4.13.8.
When
node '3' is attached as a right child of node 'C' then unbalancing occurs
because of LR. Hence LR rotation needs to be applied.
4. RL rotation
When
node '2' is attached as a left child of node 'C' then node 'A' gets unbalanced
as its balance factor becomes 2. Then RL rotation needs to be applied to
rebalance the AVL tree.
Example
- Consider an AVL tree as given below.
We have
to insert 1, 25, 28, 12 in this tree.
Insert 1
To
insert node '1' we have to attach it as a left child of '2'. This will
unbalance the tree as follows. We will apply LL rotation to preserve AVL
property of it.
Insert 25
We will
attach 25 as a right child of 18. No balancing is required as entire tree
preserves the AVL property.
Insert 28
The node
'28' is attached as a right child of 25. RR rotation is required to rebalance.
Now we
will insert 12.
To
rebalance the tree we have to apply LR rotation
Thus by
applying various rotations depending upon direction of insertion of new node
the AVL tree can be restructured.
Even
after deletion of any particular node from AVL tree, the tree has to be
restructured in order to preserve AVL property. And thereby various rotations
need to be applied.
Algorithm for deletion
The
deletion algorithm is more complex than insertion algorithm.
1.Search
the node which is to be deleted.
2. a) If
the node to be deleted is a leaf node then simply make it NULL to remove.
b) If the node to be deleted is not a leaf
node i.e. node may have one or two children,
then the node must be swapped with its inorder successor. Once the node is
swapped, we can remove this node.
3. Now
we have to traverse back up the path towards root, checking the balance factor
of every node along the path. If we encounter unbalancing in some subtree then
balance that subtree using appropriate single or double rotations.
The
deletion algorithm takes O(log n) time to delete any node
Consider
an AVL
Thus the
node 14 gets deleted from AVL tree.
4.13.4 Searching
The
searching of a node in an AVL tree is very simple. As AVL tree is basically
binary search tree, the algorithm used for searching a node from binary search
tree is the same one is used to search a node from AVL tree.
For
example: Consider an AVL tree, as given below
Now if
we want to search node with value 13 then, we will start searching process from
root.
Step 1: Compare 13 with root node
10. As 13 > 10, search right subbranch.
Step 2: Compare 13 with 18. As 13
< 18, search left subbranch.
Step 3: Compare 13 with 12. As 13
> 12, search right subbranch.
Step 4: Compare 13 with 13.
Declare now "node is found".
The
searching operation takes O (log n) time.
The main
objective here is to keep the tree balanced all the times. Such balancing
causes the depth of the tree to remain at its minimum and therefore overall
costs of search is reduced.
Ex. 4.13.1: Show the result of inserting 2, 1,
4, 5, 9, 3, 6, 7 into an empty AVL tree.
Sol. :
Ex. 4.13.2 Draw the result of inserting 20, 10
and 24 one by one into the AVL tree given below. Draw the tree after each
insertion.
Sol. :
Step 1: Insertion of 20
Ex. 4.13.3: Show the results of inserting 43,
11, 69, 72 and 30 into an initally empty AVL tree. Show the results of deleting
the nodes 11 and 72 one after the other of constructed tree.
Sol. Insertion operation
Ex. 4.13.4: Construct an AVL tree with the
values 3,1,4,5,9,2,8,7,0 into an initially empty tree. Write code for inserting
into AVL tree.
Sol.
Code for Insertion into AVL Tree
//Tree
node
typedef
struct Node
{
int
data;
int BF;
struct
Node *left;
struct
Node *right;
}node;
//
Definiton of insert function
node
*insert(int data, int *current)
{
root =
create(root, data, current);
return
root;
}
//definition
of create function
node
*create(struct Node *root, int data, int *current)
{
node
*temp1, *temp2;
if (root
== NULL)//initial node
{
root =
new node;
root->data
= = data;
root->left
= NULL;
root->right
= NULL;
root->BF
= 0;
*current
= TRUE;
return(root);
}
if
(data<root->data)
{
root->left
= create(root->left, data, current);
//
adjusting left subtree
if
(*current)
{
switch
(root->BF)
{
case
1:temp1 root->left;
if
(temp1->BF ==1)
{
printf("\n
single rotation: LL rotation");
root->left
= temp1->right;
temp1->right
= root;
root->BF
= 0;
root =
temp1;
}
else
{
printf("\n
Double rotation:LR rotation");
temp2=temp1->right;
temp1->right
= temp2->left;
temp2->left=temp1;
root->left
= temp2->right;
temp2->right
= root;
if
(temp2->BF == -1)
root->BF
= -1;
else
root->BF
= 0;
if
(temp2->BF == -1)
temp1->BF
= 1;
else
temp1->BF
= 0;
root =
temp2;
}
root->BF
= :0;
*
current = FALSE;
break;
case 0:
root->BF
= 1;
break;
case 1:
root->BF
= 0;
*current
= FALSE;
}//end
of switch
}//inner
if
}//outer
if
if (data
> root -> data)
{
root->right=create(root->right,
data, current);
//adjusting
the right subtree
if
(*current != NULL)
{
switch
(root->BF)
{
case 1:
root->BF
= 0;
*current
= FALSE;
break;
case 0:
root->BF
= -1;
break;
case-1:
temp1 =
root->right;
if
(temp1->BF == -1)
{
printf("\n
single rotation:RR rotation");
root->right
= temp1->left;
temp1->left
= root;
root->BF
= 0;
root =
temp1;
}
else
{
printf("\n
Double rotation:RL rotation");
temp2 = temp1->left;
temp1->left
= temp2->right;
temp2->right
= temp1;
root->right
temp2->left;
temp2->left
= root;
if
(temp2->BF == -1)
root->BF
= 1;
else
root->BF
= 0;
if
(temp2->BF == 1)
temp1->BF
= -1;
else
temp1->BF
= 0;
root
=temp2;
}
root->BF
= 0;
*
current = FALSE;
}
}
}
return(root);
}
void
main()
{
node
*root = NULL;
int
current;
//calling
insert function by passing values
root =
insert(40, ¤t);
root =
insert(50, ¤t);
root =
insert(70, ¤t);
….
}
Ex. 4.13.5 Define AVL Tree and starting with an
empty AVL search following elements in the given order 35, 45, 65, 55,75,15,
25.
Sol. AVL Tree Refer section 4.13.
Ex. 4.13.6: Write a routine for AVL tree
insertion. Insert the following elements in the empty tree and how do you
balance the tree after each element insertion Elements: 2, 5, 4, 6, 7, 9, 8, 3,
1, 10
Sol.
:
Ex. 4.13.7: Implementation of AVL tree.
Sol. :
/**************************************************************
This
program performs the insertion and deletion operations on an AVL tree
**************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define
FALSE 0
#define
TRUE 1
//Tree
node
typedef
struct Node
{
int
data;
int BF;
struct
Node *left;
struct
Node *right;
}node;
node
*insert(int data, int *current)
{
node
*create(node *root,int data, int *current);
node
*root;1
root=create(root,data,current);
return
root;
}
node
*remove(node *root,int data, int *current);
node
*find_succ(node *temp,node *root, int *current);
node
*right_rotation(node *root, int *current);
node
*left_rotation(node *root, int *current);
void
display(node *root);
node
*create(struct Node *root,int data, int *current)
{
node
*temp1,*temp2;
if(root
== NULL)
{
root =
new node;
root->data=data;
root->left=NULL;
root->right=NULL;
root->BF=0;
*current=TRUE;
return(root);
}
if(data<root->data)
{
root->left=create(root->left,data,current);
//
adjusting left subtree
if(*current)
{
switch(root->BF)
{
case
1:temp1= root->left;
if(temp1->BF==1)
{
printf("\n
single rotation: LL rotation");
root->left=temp1->right;
temp1->right=root;
root->BF=0;
root=temp1;
}
else
{
printf("\n
Double roation:LR rotation");
temp2=temp1->right;
temp1->right=temp2->left;
temp2->left=temp1;
root->left=temp2->right;
temp2->right=root;
if(temp2->BF==1)
root->BF=-1;
else
root->BF=0;
if(temp2->BF==-1)
temp1->BF=1;
else
temp1->BF=0;
root=temp2;
}
root->BF=0;
*current=FALSE;
break;
case 0:
root->BF=1;
break;
case -1:
root->BF=0;
*current=FALSE;
}
}
}
if(data>
root->data)
{
root->right=create(root->right,data,current);
//adjusting
the right subtree
if(*current!=
NULL)
{
case 1:
root->BF=0;
*current=FALSE;
break;
case 0:
root->BF=-1;
break;
case -1:
temp1=root->right;
if(temp1->BF==-1)
{
printf("\n
single rotation:RR rotation")
root->right=temp1->left;
temp1->left=root;
root->BF=0;
root=temp1;
}
else
{
printf("\n
Double rotation:RL rotation");
temp2=temp1->left;
temp1->left=temp2->right;
temp2->right=temp1;
root->right=temp2->>left;
temp2->left=root;
if(temp2->BF==-1)
root->BF=1;
else
root->BF=0;
if(temp2->BF==1)
temp1->BF=-1;
else
temp1->BF=0;
root=temp2;
}
root->BF=0;
*
current=FALSE;
}
}
}
return(root);
}
/*
Display
of Tree in inorder fashion
*/
void
display(node *root)
{
if(root!=
NULL)
{
display(root->left);
printf("%d",root->data);
display(root->right);
}
}
/*
Deletion
of desired node the tree
*/
node
*remove(node *root,int data, int *current)
{
node
*temp;
if(root->data==13)
printf("%d",root->data);
if(root
== NULL)
{
printf("\n
Empty Tree!!!");
return
(root);
}
else
{
if(data<root->data)
{
root->left=remove(root->left,data,current);
if(*current)
root=right_rotation(root,current);
}
else
{
if(data>root->data)
root->right-remove(root->right,data,current);
if(*current)
root-left_rotation(root,
current);
}
else
{
temp=root;
if(temp->right==
NULL)
{
root=temp->left;
*current=TRUE;
delete(temp);
}
else
{
if(temp->left==
NULL)
{
root=temp->right;
*
current=TRUE;
delete(temp);
}
else
{
temp->right=find_succ(temp->right,temp,
current);
if(*current)
root=left_rotation(root,current);
}
}
}
}
}
return
(root);
}
node
*find_succ(node *succ,node *temp,int *current)
{
node
*temp1=succ;
if(succ->left!=
NULL)
{
succ->left=find_succ(succ->left,temp,current);
if(*current)
succ=right_rotation(succ,current);
}
else
{
temp1=succ;
temp->data=succ->data;
succ
succ->right;
delete
temp1;
*current=TRUE;
}
return
(succ);
}
node
*right_rotation(node *root, int *current)
{
node
*temp1,*temp2;
switch(root->BF)
{
case 1:
root->BF=0;
break;
case 0:
root->BF
-1;
*current=FALSE;
break;
case -1:
temp1=root->right;
if(temp1->BF<=0)
{
printf("\n
single rotation: RR rotation");
root->right=temp1->left;
temp1->left=root;
if(temp1->BF==0)
{
root->BF=-1;
temp1->BF=1;
*current=FALSE;
}
else
{
root->BF=temp1->BF=0
}
root=temp1;
}
else
{
printf("\n
Double Rotation:RL rotation");
temp2=temp1->left;
temp1->left=temp2->right;
temp2->right=temp1;
root->right=temp2->left;
temp2->left=root;
if(temp2->BF==-1)
root->BF=1;
else
root->BF=0;
if(temp2->BF==1)
temp1->BF=-1;
else
temp1->BF=0;
root=temp2;
temp2->BF=0;
}
}
return
(root);
}
node
*left_rotation(node *root,int *current)
{
node
*temp1,*temp2;
switch(root->BF)
{
case 1:
root->BF=0;
break;
Case 0:
root->BF=1;
*current=FALSE;
break;
Case 1:
temp1=root->left;
if(temp1->BF>=0)
{
printf("\nsingle
rotation LL rotation");
root->left=temp1->right;
temp1->right=root;
if(temp1->BF==0)
{
root->BF=1;
temp1->BF=-1;
*current=FALSE;
}
else
{
root->BF=temp1->BF=0;
}
root=temp1;
}
else
{
printf("\nDouble
rotation:LR rotation");
temp2=temp1->right;
temp1->right-temp2->left;
temp2->left=temp1;
root->left=temp2->right;
temp2->right=root;
if(temp2->BF==1)
root->BF=-1;
else
root->BF=0;
if(temp2->BF==-1)
temp1->BF=1;
else
temp1->BF=0;
root=temp2;
temp2->BF=0;
}
}
return
root;
}
void
main()
{
node
*root=NULL;
int
current;
clrscr();
root=insert(40,¤t);
root=insert(50,¤t);
root=insert(70,¤t);
printf("\n");
display(root);
printf("\n");
root=insert(30,¤t);
printf("\n");
display(root);
root=insert(20,¤t);
printf("\n");
display(root);
root=insert(45,¤t);
printf("\n");
display(root);
root=insert(25,¤t);
printf("\n");
display(root);
root=insert(10,¤t);
printf("\n");
display(root);
root=insert(5,¤t);
printf("\n");
display(root);
root=insert(22,¤t);
printf("\n");
display(root);
root=insert(1,
¤t);
printf("\n");
display(root);
root=insert(35,¤t);
printf("\n\nFinal
AVL tree is: \n");
display(root);
printf("\n
Removing node 20");
root
remove(root,20,¤t);
printf("\n
Removing node 45");
root
remove(root,45,¤t);
printf("\n\n
AVL tree after deletion of a node: \n");
display(root);
printf("\n");
}
Output
single
rotation:RR rotation
40 50 70
30 40 50
70
single
rotation: LL rotation
20 30 40
50 70
Double
roation:LR rotation
20 30 40
45 50 70
Double
roation:LR rotation
20 25 30
40 45 50 70
10 20 25
30 40 45 50 70
single
rotation: LL rotation
5 10 20
25 30 40 45 50 70
Double
roation:LR rotation
5 10 20
22 25 30 40 45 50 70
single
rotation: LL rotation
1 5 10
20 22 25 30 40 45 50 70
Double
roation:LR rotation
Final
AVL tree is:
1 5 10
20 22 25 30 35 40 45 50 70
Removing
node 20
single
rotation LL rotation.
Removing
node 45
AVL tree
after deletion of a node:
1 5 10
22 25 30 35 40 50 70
Review Questions
1. Explain with illustration the
various types of rotations needed to retain the properties of an AVL tree
during insertion of a node. State the time complexity of insertion of a node
into an AVL
2. Explain the following. routines in
AVL tree with example. i) Insertion, ii) Delection, iii) Single rotation, iv)
Double rotation. AU: May-14, Marks 16
3. Explain the AVL rotations with a
suitable example.
Data Structure: Unit III: Trees : Tag: : Definition, Theorem, Algorithm with Example C Programs | ADT Data Structure - AVL Trees
Data Structure
CS3301 3rd Semester CSE Dept | 2021 Regulation | 3rd Semester CSE Dept 2021 Regulation