6.red Black Trees and AVL Trees (Finalized)
6.red Black Trees and AVL Trees (Finalized)
A red node can have only black children. Or, we can say that two adjacent
nodes cannot be Red in color.
If the node does not have a left or right child, then that node is said to be a
leaf node.
So, we put the left and right children below the leaf node known as nil.
The black depth or black height of a leaf node can be defined as the number
of black that we encounter when we move from the leaf node to the root
node.
One of the key properties of the Red-Black tree is that every leaf node
should have the same black depth.
In a red-black tree, every new node is inserted with the color red.
The insertion in the red-black tree is similar to the insertion operation in
a binary search tree.
But nodes are inserted with a color property.
After insertion operation, we need to check all the properties of the red-
black tree.
If all the properties are not satisfied, we perform the following operation
to make it a red-black tree.
Every Red Black tree is a BST, But every BST need not be a Red
Black Tree
Every AVL tree is a Subset of Red black tree, But every red black tree
is not an AVL Tree.
Operations:
1. Insertion
2. Deletion
Insertion:
If the tree is empty, then we create a new node as a root node with the color
black.
If the tree is not empty, then we create a new node as a leaf node with a
color red.
If the parent of a new node is black, then exit.
If the parent of a new node is Red, then we have to check the color of the
parent's sibling of a new node.
The tree is checked to be empty so the first node added is a root and is coloured
black.
Step:2
Now, the tree is not empty so we create a new node and add the next integer
with colour red
Step:3
The nodes do not violate the binary search tree and RB tree properties;
hence we move ahead to add another node.The tree is not empty; we create a
new red node with the next integer to it. But the parent of the new node is not a
black coloured node,
The tree right now violates both the binary search tree and RB tree properties;
since parent’s sibling is NULL, we apply a suitable rotation and re-colour the
nodes.
Step:4
Now that the RB Tree property is restored, we add another node to the tree –
The tree once again violates the RB Tree balance property, so we check
for the parent’s sibling node colour, red in this case, so we just recolour the
parent and the sibling.
Step:5
We next insert the element 5, which makes the tree violate the RB
Tree balance property once again. And since the sibling is NULL, we apply
suitable rotation and recolour.
Step:6
Step:7
Now, we add the last element, 7, but the parent node of this new node
is red. Since the parent’s sibling is NULL, we apply suitable rotations (RR
rotation)
#include <stdio.h>
#include <stdlib.h>
int data;
} Node;
newNode->data = data;
return newNode;
Node* insertNode(Node* root, int data) // Function to insert a node into tree
{
Node* newNode = createNode(data);
if (root == NULL)
root = newNode;
else
parent = current;
current = current->left;
else
current = current->right;
newNode->parent = parent;
if (data < parent->data)
parent->left = newNode;
else
parent->right = newNode;
return root;
if (root != NULL)
printTree(root->left);
printTree(root->right);
}
int main()
printTree(root);
return 0;
Output:
Red-Black Tree:
5 (Red)
10 (Red)
15 (Red)
20 (Red)
25 (Red)
Deletion:
The deletion operation is more complex than insertion, as it requires not
only removing the node but also preserving the tree's balance and color properties.
Key Concepts:
The deletion operation on red black tree must be performed in such a way that it
must restore all the properties of a binary search tree and a red black tree. Follow
the steps below to perform the deletion operation on the red black tree
Case 1: If either the node to be deleted or the node’s parent is red, just delete it.
Case 2: If the node is a double black, just remove the double black (double black
occurs when the node to be deleted is a black coloured leaf node, as it adds up the
NULL nodes which are considered black coloured nodes too)
Case 3: If the double black’s sibling node is also a black node and its child nodes
are also black in color, follow the steps below .
Remove double black:
Re-colour its parent to black (if the parent is a red node, it becomes black;
if the parent is already a black node, it becomes double black)
Recolor the parent’s sibling with red
If double black node still exists, we apply other cases.
Case 4:
If the double black node’s sibling is red, we perform the following steps
Swap the colors of the parent node and the parent’s sibling node.
Case 5:
If the double black’s sibling is a black node but the sibling’s child node
that is closest to the double black is red, follows the steps below −Swap the
colors of double black’s sibling and the sibling’s child in question Rotate the
sibling node is the opposite direction of double black (i.e. if the double black is
a right child apply left rotations and vice versa)
Apply case 6:
Case 6:
If the double black’s sibling is a black node but the sibling’s child node
that is farther to the double black is red, follows the steps below Swap the colors
of double black’s parent and sibling nodes
Rotate the parent in double black’s direction (i.e. if the double black is a
right child apply right rotations and vice versa)
Remove double black:
Deletion Example
To delete the element 4, let us perform the binary search deletion first.
After performing the binary search deletion, the RB Tree property is not disturbed,
therefore the tree is left as it is.
But the RB property is violated after performing the binary search deletion, i.e., all
the paths in the tree do not hold same number of black nodes; so, we swap the
colors to balance the tree.
Then, we delete the node 3 from the tree obtained
We apply case 3 deletion as double black’s sibling node is black and its child
nodes are also black. Here, we remove the double black, recolour the double
black’s parent and sibling.
Search:
1. First, we check if the root node is the desired node. If yes, return that.
2. If the value is less than the value of the root node, apply the search
function on its left child else, apply the search function on its right child.
3. Repeat the above steps unless we find the desired value or reach the tree's
end. We can check if it's the end of the tree if we encounter a None node.
In that case, return None or False.
Example:
#include <stdio.h>
#include <stdlib.h>
enum nodeColor {
RED,
BLACK
};
struct rbNode {
};
newnode->data = data;
newnode->color = RED;
newnode->link[0] = newnode->link[1] = NULL;
return newnode;
// Insert an node
ptr = root;
if (!root) {
root = createNode(data);
return;
stack[ht] = root;
dir[ht++] = 0;
if (ptr->data == data) {
return;
}
stack[ht] = ptr;
ptr = ptr->link[index];
dir[ht++] = index;
if (dir[ht - 2] == 0) {
ht = ht - 2;
} else {
if (dir[ht - 1] == 0) {
} else {
xPtr = stack[ht - 1];
yPtr = xPtr->link[1];
xPtr->link[1] = yPtr->link[0];
yPtr->link[0] = xPtr;
xPtr->color = RED;
yPtr->color = BLACK;
xPtr->link[0] = yPtr->link[1];
yPtr->link[1] = xPtr;
if (xPtr == root) {
root = yPtr;
} else {
break;
}
} else {
ht = ht - 2;
} else {
if (dir[ht - 1] == 1) {
} else {
yPtr = xPtr->link[0];
xPtr->link[0] = yPtr->link[1];
yPtr->link[1] = xPtr;
yPtr->color = BLACK;
xPtr->color = RED;
xPtr->link[1] = yPtr->link[0];
yPtr->link[0] = xPtr;
if (xPtr == root) {
root = yPtr;
} else {
break;
root->color = BLACK;
if (!root) {
return;
ptr = root;
if ((data - ptr->data) == 0)
break;
stack[ht] = ptr;
dir[ht++] = diff;
ptr = ptr->link[diff];
if (ptr->link[1] == NULL) {
free(ptr);
root = NULL;
} else if (ptr == root) {
root = ptr->link[0];
free(ptr);
} else {
} else {
xPtr = ptr->link[1];
if (xPtr->link[0] == NULL) {
xPtr->link[0] = ptr->link[0];
color = xPtr->color;
xPtr->color = ptr->color;
ptr->color = color;
if (ptr == root) {
root = xPtr;
} else {
}
dir[ht] = 1;
stack[ht++] = xPtr;
} else {
i = ht++;
while (1) {
dir[ht] = 0;
stack[ht++] = xPtr;
yPtr = xPtr->link[0];
if (!yPtr->link[0])
break;
xPtr = yPtr;
dir[i] = 1;
stack[i] = yPtr;
if (i > 0)
yPtr->link[0] = ptr->link[0];
xPtr->link[0] = yPtr->link[1];
yPtr->link[1] = ptr->link[1];
if (ptr == root) {
root = yPtr;
color = yPtr->color;
yPtr->color = ptr->color;
ptr->color = color;
if (ht < 1)
return;
if (ptr->color == BLACK) {
while (1) {
pPtr->color = BLACK;
break;
}
if (ht < 2)
break;
if (dir[ht - 2] == 0) {
if (!rPtr)
break;
if (rPtr->color == RED) {
rPtr->color = BLACK;
if (stack[ht - 1] == root) {
root = rPtr;
} else {
dir[ht] = 0;
ht++;
rPtr->color = RED;
} else {
qPtr = rPtr->link[0];
rPtr->color = RED;
qPtr->color = BLACK;
rPtr->link[0] = qPtr->link[1];
qPtr->link[1] = rPtr;
if (stack[ht - 1] == root) {
root = rPtr;
} else {
break;
} else {
if (!rPtr)
break;
if (rPtr->color == RED) {
rPtr->color = BLACK;
if (stack[ht - 1] == root) {
root = rPtr;
} else {
dir[ht] = 1;
stack[ht - 1] = rPtr;
ht++;
rPtr->color = RED;
} else {
qPtr = rPtr->link[1];
rPtr->color = RED;
qPtr->color = BLACK;
rPtr->link[1] = qPtr->link[0];
qPtr->link[0] = rPtr;
rPtr->link[0]->color = BLACK;
if (stack[ht - 1] == root) {
root = rPtr;
} else {
break;
}
}
ht--;
if (node) {
inorderTraversal(node->link[0]);
inorderTraversal(node->link[1]);
return;
// Driver code
int main() {
while (1) {
printf("1. Insertion\t2. Deletion\n");
scanf("%d", &ch);
switch (ch) {
case 1:
scanf("%d", &data);
insertion(data);
break;
case 2:
scanf("%d", &data);
deletion(data);
break;
case 3:
inorderTraversal(root);
printf("\n");
break;
case 4:
exit(0);
default:
printf("Not available\n");
break;
printf("\n");
return 0;
Output:
1. Insertion 2. Deletion
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
3. Traverse 4. Exit
1. Insertion 2. Deletion
3. Traverse 4. Exit
5 10 15 25 30 35 40
1. Insertion 2. Deletion
3. Traverse 4. Exit
Balanced Factor:
Properties:
In figure (b), if you check the node with value 3, its left subtree has
height=2 while the right subtree’s height=0. So, the difference is mod (2-0) =
2. Hence, the AVL property is not satisfied, and it is not an AVL tree.
AVL tree performs two major operations namely Insert and Delete.
Insertion:
Deletion:
AVL Rotations:
1. Search
2. Insertion
3. Deletion
4. Traversal
Node 6 has a balance factor of -2 after the insertion of node 10. After a single
rotation towards the left, node 8 becomes the root and node 6 becomes its left
child. By doing this, the BST property also remains intact, and the tree becomes
height-balanced.
Right Rotation (RR - Single Rotation):
#include <stdio.h>
#include <stdlib.h>
struct Node
int data;
int height;
};
if(n==NULL)
return 0;
return n->height;
node->data = data;
node->left = NULL;
node->right = NULL;
node->height = 1;
return node;
return (a>b)?a:b;
if(n==NULL)
return 0;
x->right = y;
y->left = T2;
return x;
y->left = x;
x->right = T2;
return y;
if (node == NULL)
return create_Node(data);
return right_Rotate(node);
return left_Rotate(node);
node->left = left_Rotate(node->left);
return right_Rotate(node);
node->right = right_Rotate(node->right);
return left_Rotate(node);
return node;
}
void preOrder(struct Node *root)
if(root != NULL)
preOrder(root->left);
preOrder(root->right);
int main()
preOrder(root);
return 0;
}
Output:
24 22 11 56 35 63
Constructing an AVL tree
Example: H, I, J, B, A, E, C, F, D, G, K, L
1. Insert H, I, J
2. Insert B, A
The AVL tree is always height-balanced, and its height is always O (log
N), where N is the total number of nodes in the tree.
The time complexities of all the operations are better than BSTs as the
AVL tree has the worst-case time complexity of all operations as O(log
N), while in BST, it is O(N).
AVL trees have self-balancing properties.
AVL trees are not skewed.
AVL trees perform better searching operations than Red-Black Trees
It shows better search time complexity.
Less balanced than the AVL Tree. More balanced than the Red-Black
Tree.
Only requires keeping track of colors Each node requires to keep track
assigned to a node. of balanced factors.