0% found this document useful (0 votes)
43 views

Final Project

The document summarizes an AVL tree project that implements a self-balancing binary search tree. It discusses that AVL trees guarantee O(log n) time for operations by ensuring the height difference between any node's left and right subtrees is at most 1. It then covers AVL tree operations like insertion which may require rotations to rebalance the tree if it becomes unbalanced. Sample insertion of nodes is provided to demonstrate rebalancing through left and right rotations.

Uploaded by

Raza Bhatti
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views

Final Project

The document summarizes an AVL tree project that implements a self-balancing binary search tree. It discusses that AVL trees guarantee O(log n) time for operations by ensuring the height difference between any node's left and right subtrees is at most 1. It then covers AVL tree operations like insertion which may require rotations to rebalance the tree if it becomes unbalanced. Sample insertion of nodes is provided to demonstrate rebalancing through left and right rotations.

Uploaded by

Raza Bhatti
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

AVL TREE PROJECT

Implementation of AVL

Document Prepared By
Zeeshan Ahmad S2019027005
Ali Raza S2019027015
Fawad Afzal S2019027032
AVL TREE PROJECT
1. Definition

AVL tree is a self-balancing Binary Search Tree. The difference between heights of left subtree
and right subtree cannot be more than one for all nodes.

1.1. Why AVL Tree

Most of the Binary Search Tree operations take O (h) time where h is the height of the BST. The
cost of these operations may become O (n) for a skewed Binary tree. In a skewed binary tree,
all nodes except one have only one child node. The remaining node has no child. If we make
sure that height of the tree remains O (Log n) after every insertion and deletion, then we can
guarantee an upper bound of O (Log n) for all these operations. The height of an AVL tree is
always O (Log n) where n is the number of nodes in the tree.

1.2. Balance Factor

In a binary tree the balance factor of a node is defined to be the height difference


Balance Factor = Height Right subtree - Height Left subtree

A Binary tree is defined to be an AVL if the balance factor = {-1 0 1} of each node
holds this value. A node with 1 balance factor is call Left Heavy and a node with -1 balance
factor is called Right Heavy, and a node with 0 balance factor is called balanced.

2. Operation

2.1. Insertion

When inserting a node into an AVL tree, you initially follow the same process as
inserting into a Binary Search Tree. If the tree is empty, then the node is inserted as
the root of the tree. In case the tree has not been empty then we go down the root,
and recursively go down the tree searching for the location to insert the new node.
This traversal is guided by the comparison function. In this case, the node always
replaces a NULL reference (left or right) of an external node in the tree i.e., the node
is either made a left-child or a right-child of the external node.

To make sure that the given tree remains AVL after every insertion, we must
augment the standard BST insert operation to perform some re-balancing.

 Left rotation

If a tree becomes unbalanced, when a node is inserted into the right subtree of
the right subtree, then we perform a single left rotation
Node A has become unbalanced as a node is inserted in the right subtree of A's
right subtree. We perform the left rotation by making A the left-subtree of B.

 Right rotation

AVL tree may become unbalanced, if a node is inserted in the left subtree of the
left subtree. The tree then needs a right rotation.

 Left-Right rotation

Double rotations are slightly complex version of already explained versions of


rotations. To understand them better, we should take note of each action
performed while rotation. Let's first check how to perform Left-Right rotation. A
left-right rotation is a combination of left rotation followed by right rotation.

A node has been inserted into the right subtree of the left subtree. This
makes C an unbalanced node. These scenarios cause AVL tree to perform
left-right rotation. We first perform the left rotation on the left subtree of C.
This makes A, the left subtree of B. Node C is still unbalanced, however
now, it is because of the left-subtree of the left-subtree.
We shall now right-rotate the tree, making B the new root node of
this subtree. C now becomes the right subtree of its own left subtree.
Now the tree is balanced.

 Right-Left rotation
The second type of double rotation is Right-Left Rotation. It is a combination of
right rotation followed by left rotation.

A node has been inserted into the left subtree of the right subtree. This makes A, an
unbalanced node with balance factor 2. First, we perform the right rotation
along C node, making C the right subtree of its own left subtree B. Now, B becomes
the right subtree of A. Node A is still unbalanced because of the right subtree of its
right subtree and requires a left rotation.
A left rotation is performed by making B the new root node of the
subtree. A becomes the left subtree of its right subtree B. The tree is now balanced

Algorithm:

Insert (A, node) {


If (tree == null) {
A = new node
A.data = node
A.left = null
A.right = null
}
Else if (node < A.data ){
A.left = Insert (A.left, node)
A = balance (A)
}
Else if (node >= A.data ){
A.right = Insert (A.right, node)
A = balance (A)
}
Return A
}

Code in C++:

avl *avl_tree::insert(avl *r, int v) {


if (r == NULL) {
r = new avl;
r->data = v;
r->left = NULL;
r->right = NULL;
return r;
}
else if (v< r->data) {
r->left = insert(r->left, v);
r = balance(r);
}
else if (v >= r->data) {
r->right = insert(r->right, v);
r = balance(r);
} return r;
}

int avl_tree::height(avl *t) {


int h = 0;
if (t != NULL) {
int l_height = height(t->left);
int r_height = height(t->right);
int max_height = max(l_height, r_height);
h = max_height + 1;
}
return h;
}

int avl_tree::difference(avl *t) {


int l_height = height(t->left);
int r_height = height(t->right);
int b_factor = l_height - r_height;
return b_factor;
}

avl *avl_tree::rr_rotat(avl *parent) {


avl *t;
t = parent->right;
parent->right = t->left;
t->left = parent;
cout << " Right-Right Rotation " << endl;
return t;
}

avl *avl_tree::ll_rotat(avl *parent) {


avl *t;
t = parent->left;
parent->left = t->right;
t->right = parent;
cout << " Left-Left Rotation " << endl;
return t;
}

avl *avl_tree::lr_rotat(avl *parent) {


avl *t;
t = parent->left;
parent->left = rr_rotat(t);
cout << " Left-Right Rotation " << endl ;
return ll_rotat(parent);
}

avl *avl_tree::rl_rotat(avl *parent) {


avl *t;
t = parent->right;
parent->right = ll_rotat(t);
cout << "Right-Left Rotation" << endl ;
return rr_rotat(parent);
}

avl *avl_tree::balance(avl *t) {


int bal_factor = difference(t);
if (bal_factor > 1) {
if (difference(t->left) > 0)
t = ll_rotat(t);
else
t = lr_rotat(t);
}
else if (bal_factor < -1) {
if (difference(t->right) > 0)
t = rl_rotat(t);
else
t = rr_rotat(t);
}
return t;
}

2.2. Dry Run of Insertion

Insert these values in Avl


24 2 32 7 42 37 40 20 42 5

Insert 24,2,32
0
24

0 0

2 32

Insert 7, 42, 37 with left left rotation


-1
24

-1 -2

2 32

1
0
7 42
Left Rotation
0
37
-1
24

-1 -2

2 32

1 Left Rotation
0
7 37

0
42

0
24

-1 0

2 37

0 0
0
7 32 42

Insert 40 , 20 with left rotation

-1
24

-2 -1
Left Rotation
2 37

-1 0 1
7 32 42

0 0
20 40
-1
24

0 -1
Left Rotation
7 37

0 0
0 1
2 20 32 42

0
40

Insert 42, 5

-1
24

0 -1
Left Rotation
7 37

0 0
0 1
2 20 32 42

0 0
5 40 42

2.3. Searching
Finding a specific node in an AVL tree can be done the same way as that of balanced or
unbalanced BST.
Algorithm:

Find (node, key) {


If (node! = NULL) {
If (node == key)
{
Print node
}
Else
{
Print Null
}
If (key < node->data)
{
Find (node. Left, key);
}
Else
{
Find (node. Right, key);
}
}
}

The procedure begins its search at the root and traces a simple path downward in the tree. For
each node it encounters, it compares the key k with node. If the two are equal, the search
terminates. If key is smaller than the search continues in the left subtree of node, if key is larger
than the search continues in the right subtree. The nodes encountered during the recursion form
a simple path downward from the root of the tree, and thus the running time of Find is O.(h),
where h is the height of the tree.

Code in C++:

void avl_tree::find(avl *node, int key) {


if (node != NULL) {
if (node->data == key)
{
cout << node->data;
}
else
{
cout << "Null ";
}
if (key < node->data){
find(node->left, key);
}
else
{
find(node->right, key);
}
}
}
2.4. Print Tree
Algorithm:

Print ( tree, q )
{
Print (tree.right, q+1)
If (tree == r) // R is the length of the tree
Print root.
For (i = 0 , I < l and tree != r)
{
Print tree
Print (tree.left ,q+1)
}
}

void avl_tree::print(avl *p, int l) {

if (p != NULL) {
print(p->right, l + 1);
cout << " ";
if (p == r)
cout << "Root -> ";
for (int i = 0; i < l&& p != r; i++)
cout << " ";
cout << p->data;
print(p->left, l + 1);
}
}

Unlike linear data structures which have only one logical way to traverse them, trees
can be traversed in different ways. Following are the generally used ways for
traversing trees.

Depth First Traversals:

 In Order (Left, Root, Right)

void avl_tree::inorder(avl *t) {


if (t == NULL)
return;
inorder(t->left);
cout << t->data << " ";
inorder(t->right);
}

 Preorder (Root, Left, Right)


void avl_tree::preorder(avl *t) {
if (t == NULL)
return;
cout << t->data << " ";
preorder(t->left);
preorder(t->right);
}

 Post Order (Left, Right, Root)

void avl_tree::postorder(avl *t) {


if (t == NULL)
return;
postorder(t->left);
postorder(t->right);
cout << t->data << " ";
}

You might also like