Red Black Trees
Red Black Trees
In Red-Black trees, also known as RB trees, there are different conditions to follow while assigning the
colours to the nodes.
Every path in the tree (from the root node to the leaf node) must have the same amount of
black coloured nodes.
Even though AVL trees are more balanced than RB trees, with the balancing algorithm in AVL trees
being stricter than that of RB trees, multiple and faster insertion and deletion operations are made
more efficient through RB trees.
Fig: RB trees
Insertion
Deletion
Page 2 of 22
Search
Insertion operation
Insertion operation of a Red-Black tree follows the same insertion algorithm of a binary search tree.
The elements are inserted following the binary search property and as an addition, the nodes are color
coded as red and black to balance the tree according to the red-black tree properties.
Follow the procedure given below to insert an element into a red-black tree by maintaining both binary
search tree and red black tree properties.
Case 1 − Check whether the tree is empty; make the current node as the root and color the node black
if it is empty.
Case 2 − But if the tree is not empty, we create a new node and color it red. Here we face two different
cases −
If the parent of the new node is a black colored node, we exit the operation and tree is left as
it is.
If the parent of this new node is red and the color of the parent's sibling is either black or if it
does not exist, we apply a suitable rotation and recolor accordingly.
If the parent of this new node is red and color of the parent's sibling is red, recolor the parent,
the sibling and grandparent nodes to black. The grandparent is recolored only if it is not the
root node; if it is the root node recolor only the parent and the sibling.
Example
Let us construct an RB Tree for the first 7 integer numbers to understand the insertion operation in
detail −
The tree is checked to be empty so the first node added is a root and is colored black.
Now, the tree is not empty so we create a new node and add the next integer with color red,
Page 3 of 22
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 colored 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 recolor the nodes.
Page 4 of 22
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
color, red in this case, so we just recolor the parent and the sibling.
Page 5 of 22
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 recolor.
Page 6 of 22
Now, we insert element 6, but the RB Tree property is violated and one of the insertion cases need to
be applied −
The parent's sibling is red, so we recolor the parent, parent's sibling and the grandparent nodes since
the grandparent is not the root node.
Page 7 of 22
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)
Page 8 of 22
Explore our latest online courses and learn new skills at your own pace. Enroll and become a certified
expert to boost your career.
Deletion operation
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 colored leaf node, as it adds up the NULL nodes which are considered
black colored 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 −
Recolor 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)
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 −
Rotate the parent in double black's direction (i.e. if the double black is a right child apply right
rotations and vice versa)
Example
Considering the same constructed Red-Black Tree above, let us delete few elements from the tree.
Page 10 of 22
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.
Page 11 of 22
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.
Applying binary search deletion, we delete node 3 normally as it is a leaf node. And we get a double
node as 3 is a black colored node.
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, recolor the double black's parent and sibling.
All the desired nodes are deleted and the RB Tree property is maintained.
Page 13 of 22
Search operation
The search operation in red-black tree follows the same algorithm as that of a binary search tree. The
tree is traversed and each node is compared with the key element to be searched; if found it returns a
successful search. Otherwise, it returns an unsuccessful search.
Complete implementation
Following are the complete implementations of Red Black Tree in various programming languages −
Open Compiler
}
}
// Inorder
void inOrderHelper(NodePtr node) {
if (node != TNULL) {
inOrderHelper(node->left);
cout << node->data << " ";
inOrderHelper(node->right);
}
}
// Post order
void postOrderHelper(NodePtr node) {
if (node != TNULL) {
postOrderHelper(node->left);
postOrderHelper(node->right);
cout << node->data << " ";
}
}
NodePtr searchTreeHelper(NodePtr node, int key) {
if (node == TNULL || key == node->data) {
return node;
}
if (key < node->data) {
return searchTreeHelper(node->left, key);
}
return searchTreeHelper(node->right, key);
}
// For balancing the tree after deletion
void deleteFix(NodePtr x) {
NodePtr s;
while (x != root && x->color == 0) {
if (x == x->parent->left) {
s = x->parent->right;
if (s->color == 1) {
s->color = 0;
x->parent->color = 1;
leftRotate(x->parent);
s = x->parent->right;
}
if (s->left->color == 0 && s->right->color == 0) {
s->color = 1;
x = x->parent;
Page 15 of 22
} else {
if (s->right->color == 0) {
s->left->color = 0;
s->color = 1;
rightRotate(s);
s = x->parent->right;
}
s->color = x->parent->color;
x->parent->color = 0;
s->right->color = 0;
leftRotate(x->parent);
x = root;
}
} else {
s = x->parent->left;
if (s->color == 1) {
s->color = 0;
x->parent->color = 1;
rightRotate(x->parent);
s = x->parent->left;
}
if (s->right->color == 0 && s->right->color == 0) {
s->color = 1;
x = x->parent;
} else {
if (s->left->color == 0) {
s->right->color = 0;
s->color = 1;
leftRotate(s);
s = x->parent->left;
}
s->color = x->parent->color;
x->parent->color = 0;
s->left->color = 0;
rightRotate(x->parent);
x = root;
}
}
}
x->color = 0;
}
void rbTransplant(NodePtr u, NodePtr v) {
Page 16 of 22
if (u->parent == nullptr) {
root = v;
} else if (u == u->parent->left) {
u->parent->left = v;
} else {
u->parent->right = v;
}
v->parent = u->parent;
}
void deleteNodeHelper(NodePtr node, int key) {
NodePtr z = TNULL;
NodePtr x, y;
while (node != TNULL) {
if (node->data == key) {
z = node;
}
if (node->data <= key) {
node = node->right;
} else {
node = node->left;
}
}
if (z == TNULL) {
cout << "Key not found in the tree" << endl;
return;
}
y = z;
int y_original_color = y->color;
if (z->left == TNULL) {
x = z->right;
rbTransplant(z, z->right);
} else if (z->right == TNULL) {
x = z->left;
rbTransplant(z, z->left);
} else {
y = minimum(z->right);
y_original_color = y->color;
x = y->right;
if (y->parent == z) {
x->parent = y;
} else {
rbTransplant(y, y->right);
Page 17 of 22
y->right = z->right;
y->right->parent = y;
}
rbTransplant(z, y);
y->left = z->left;
y->left->parent = y;
y->color = z->color;
}
delete z;
if (y_original_color == 0) {
deleteFix(x);
}
}
// For balancing the tree after insertion
void insertFix(NodePtr k) {
NodePtr u;
while (k->parent->color == 1) {
if (k->parent == k->parent->parent->right) {
u = k->parent->parent->left;
if (u->color == 1) {
u->color = 0;
k->parent->color = 0;
k->parent->parent->color = 1;
k = k->parent->parent;
} else {
if (k == k->parent->left) {
k = k->parent;
rightRotate(k);
}
k->parent->color = 0;
k->parent->parent->color = 1;
leftRotate(k->parent->parent);
}
} else {
u = k->parent->parent->right;
if (u->color == 1) {
u->color = 0;
k->parent->color = 0;
k->parent->parent->color = 1;
k = k->parent->parent;
} else {
if (k == k->parent->right) {
Page 18 of 22
k = k->parent;
leftRotate(k);
}
k->parent->color = 0;
k->parent->parent->color = 1;
rightRotate(k->parent->parent);
}
}
if (k == root) {
break;
}
}
root->color = 0;
}
void printHelper(NodePtr root, string indent, bool last) {
if (root != TNULL) {
cout << indent;
if (last) {
cout << "R----";
indent += " ";
} else {
cout << "L----";
indent += "| ";
}
string sColor = root->color ? "RED" : "BLACK";
cout << root->data << "(" << sColor << ")" << endl;
printHelper(root->left, indent, false);
printHelper(root->right, indent, true);
}
}
public:
RedBlackTree() {
TNULL = new Node;
TNULL->color = 0;
TNULL->left = nullptr;
TNULL->right = nullptr;
root = TNULL;
}
void preorder() {
preOrderHelper(this->root);
}
void inorder() {
Page 19 of 22
inOrderHelper(this->root);
}
void postorder() {
postOrderHelper(this->root);
}
NodePtr searchTree(int k) {
return searchTreeHelper(this->root, k);
}
NodePtr minimum(NodePtr node) {
while (node->left != TNULL) {
node = node->left;
}
return node;
}
NodePtr maximum(NodePtr node) {
while (node->right != TNULL) {
node = node->right;
}
return node;
}
NodePtr successor(NodePtr x) {
if (x->right != TNULL) {
return minimum(x->right);
}
NodePtr y = x->parent;
while (y != TNULL && x == y->right) {
x = y;
y = y->parent;
}
return y;
}
NodePtr predecessor(NodePtr x) {
if (x->left != TNULL) {
return maximum(x->left);
}
NodePtr y = x->parent;
while (y != TNULL && x == y->left) {
x = y;
y = y->parent;
}
return y;
}
Page 20 of 22
void leftRotate(NodePtr x) {
NodePtr y = x->right;
x->right = y->left;
if (y->left != TNULL) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == nullptr) {
this->root = y;
} else if (x == x->parent->left) {
x->parent->left = y;
} else {
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void rightRotate(NodePtr x) {
NodePtr y = x->left;
x->left = y->right;
if (y->right != TNULL) {
y->right->parent = x;
}
y->parent = x->parent;
if (x->parent == nullptr) {
this->root = y;
} else if (x == x->parent->right) {
x->parent->right = y;
} else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
}
// Inserting a node
void insert(int key) {
NodePtr node = new Node;
node->parent = nullptr;
node->data = key;
node->left = TNULL;
node->right = TNULL;
node->color = 1;
Page 21 of 22
NodePtr y = nullptr;
NodePtr x = this->root;
while (x != TNULL) {
y = x;
if (node->data < x->data) {
x = x->left;
} else {
x = x->right;
}
}
node->parent = y;
if (y == nullptr) {
root = node;
} else if (node->data < y->data) {
y->left = node;
} else {
y->right = node;
}
if (node->parent == nullptr) {
node->color = 0;
return;
}
if (node->parent->parent == nullptr) {
return;
}
insertFix(node);
}
NodePtr getRoot() {
return this->root;
}
void deleteNode(int data) {
deleteNodeHelper(this->root, data);
}
void printTree() {
if (root) {
printHelper(this->root, "", true);
}
}
};
int main() {
RedBlackTree V;
V.insert(24);
Page 22 of 22
V.insert(33);
V.insert(42);
V.insert(51);
V.insert(60);
V.insert(40);
V.insert(22);
V.printTree();
cout << endl
<< "After deleting an element" << endl;
V.deleteNode(40);
V.printTree();
}
Output
R----33(BLACK)
L----24(BLACK)
| L----22(RED)
R----51(RED)
L----42(BLACK)
| L----40(RED)
R----60(BLACK)