- Definition & Properties of R B Tree
- Definition
- Properties of Red-Black Tree (RBT)
- Core Components and Architecture
- 🧱 Node Structure
- 🔄 Insertion and Rebalancing Logic
- 🧮 Deletion and Rebalancing
- Red-Black Tree Insertion Algorithm
- Red-Black Tree C Program
- Working of R B Tree with Example
- Problem:
- ✅ Step-by-Step Execution:
- 🔢 Inserting 10:
- 🔢 Inserting 20:
- 🔢 Inserting 30:
- 🔁 Fixing the Tree:
- 🔢 Inserting 15:
- 🔁 Fixing the Tree:
- ✅ Final Red-Black Tree After Inserting [10, 20, 30, 15]:
- What Just Happened?
- Learning Summary:
- Red-Black Tree Time and Space Complexity
- Why Time Complexity is O(log n)?
- Space Complexity
- Valid Parent-Child Color Combinations in a Red-Black Tree:
- 🌐 Real-Time Use Cases of R B Tree
- Advantages of Red-Black Tree
- Disadvantages of Red-Black Tree
- ❓FAQs on Red-Black Tree (RBT)
- Q1. What is a Red-Black Tree in simple words?
- Q2. Why do we use Red-Black Trees?
- Q3. What are the main properties of a Red-Black Tree?
- Q4. What are the advantages of Red-Black Trees?
- Q5. What are the disadvantages of Red-Black Trees?
- Q6. Where are Red-Black Trees used in real life?
- Q7. Is Red-Black Tree faster than AVL Tree?
- Q8. What is the time complexity of Red-Black Tree operations?
A Red-Black Tree is a type of self-balancing binary search tree where each node has a color — either red or black. It follows specific rules related to these colors to keep the tree balanced after every insertion or deletion. This balance helps in keeping operations like search, insert, and delete efficient, taking only O(log n) time.
What makes a Red-Black Tree special is that each node is either red or black in color, and there are a few rules about how these colors are arranged. These color rules ensure that the tree doesn’t become too tall, so we can always reach any element in about log(n) steps. This is very important, because if the tree becomes unbalanced, some operations can become very slow.
In real-world use, Red-Black Trees are used in many computer systems. For example:
- In C++ STL (like
std::map
) and Java’s TreeMap, which need fast access to sorted data. - In operating systems like Linux, Red-Black Trees are used to manage tasks and memory efficiently.
- They are also useful in embedded systems and real-time applications where we need quick and predictable performance.
The biggest advantage of Red-Black Trees is that they stay balanced automatically without needing too many changes, which makes them reliable and fast in most situations.
Definition & Properties of R B Tree
Definition
A Red-Black Tree is a special type of Binary Search Tree (BST) that keeps itself balanced by using red and black colors on its nodes.
It follows some simple color rules to make sure the tree does not become too tall or unbalanced. This helps us do things like searching, inserting, and deleting data quickly, even when there are many elements.
In short:
🟥🔲 Red-Black Tree = Normal BST + Extra Rules to Stay Balanced Using Colors
Properties of Red-Black Tree (RBT)
- Each node is either red or black.
👉 Every node in the tree must have a color — either Red or Black. - The root node is always black.
👉 The very first (top-most) node of the tree must always be black. - All NULL (leaf) nodes are considered black.
👉 Even though NULL nodes (empty children) are not shown, they are treated as black nodes in the tree’s logic. - Red nodes cannot have red children (no two red nodes in a row).
👉 If a node is red, its children must be black. This avoids having red nodes stacked together. - Every path from a node to its leaf nodes must have the same number of black nodes.
👉 Called black-height, this rule ensures all paths in the tree are roughly the same length, keeping the tree balanced.
These rules help the Red-Black Tree stay balanced, which means the longest path is not much longer than the shortest. This ensures that operations like search, insert, and delete stay fast — always within O(log n) time.
Core Components and Architecture
🧱 Node Structure
Each node in a red-black tree contains the following:
struct RBTNode {
int data;
bool isRed;
RBTNode* left;
RBTNode* right;
RBTNode* parent;
};
data
: stores the keyisRed
: indicates the color of the nodeleft
,right
: pointers to child nodesparent
: pointer to the parent node for easy rotations
🔄 Insertion and Rebalancing Logic
The insertion process in a Red-Black Tree involves two steps:
- Standard BST Insertion: Insert the node as in a regular BST, and color it red.
- Fixing the Tree (Rebalancing): After insertion, check if Red-Black properties are violated. If they are, perform:
- Recoloring
- Left or Right Rotations
The rebalancing process ensures that the height of the tree remains logarithmic.
🧮 Deletion and Rebalancing
Deletion is more complex and involves:
- Replace the node as in BST
- If deleted node was black, it might cause imbalance in black-height → fix using:
- Recoloring
- Rotations
- Double black logic (for balancing missing black node)
Red-Black Tree Insertion Algorithm
Algorithm: InsertNode_RBT(root, data)
Input: Root node of the Red-Black Tree, new data to insert
Output: Balanced Red-Black Tree after insertion
1. Create a new node with the given data, color it RED.
2. Perform standard Binary Search Tree insertion to place the node.
3. Fix any Red-Black Tree property violations:
a. If the parent is BLACK → Done (no violation).
b. If the parent is RED:
i. If uncle is also RED:
- Recolor parent and uncle to BLACK
- Recolor grandparent to RED
- Repeat the process from grandparent
ii. If uncle is BLACK:
- Perform appropriate rotations (Left, Right, or both)
- Recolor the nodes accordingly
4. Make sure the root is always colored BLACK.
Red-Black Tree C Program
#include <stdio.h>
#include <stdlib.h>
enum Color { RED, BLACK };
// Structure of Red-Black Tree Node
typedef struct Node {
int data;
int color;
struct Node *left, *right, *parent;
} Node;
// Function to create a new Red-Black Tree node
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->color = RED; // New node is always RED initially
newNode->left = newNode->right = newNode->parent = NULL;
return newNode;
}
// Function to perform Left Rotation
Node* leftRotate(Node* root, Node* x) {
Node* y = x->right;
x->right = y->left;
if (y->left != NULL)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == NULL)
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
return root;
}
// Function to perform Right Rotation
Node* rightRotate(Node* root, Node* x) {
Node* y = x->left;
x->left = y->right;
if (y->right != NULL)
y->right->parent = x;
y->parent = x->parent;
if (x->parent == NULL)
root = y;
else if (x == x->parent->right)
x->parent->right = y;
else
x->parent->left = y;
y->right = x;
x->parent = y;
return root;
}
// Fix Red-Black Tree violations after insertion
Node* fixViolation(Node* root, Node* pt) {
Node* parent = NULL;
Node* grandparent = NULL;
while ((pt != root) && (pt->color != BLACK) && (pt->parent->color == RED)) {
parent = pt->parent;
grandparent = parent->parent;
// Parent is left child of grandparent
if (parent == grandparent->left) {
Node* uncle = grandparent->right;
// Case 1: Uncle is RED → Recoloring
if (uncle != NULL && uncle->color == RED) {
grandparent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
pt = grandparent;
}
else {
// Case 2: Node is right child → Left Rotation
if (pt == parent->right) {
pt = parent;
root = leftRotate(root, pt);
parent = pt->parent;
}
// Case 3: Node is left child → Right Rotation
parent->color = BLACK;
grandparent->color = RED;
root = rightRotate(root, grandparent);
}
}
// Parent is right child of grandparent
else {
Node* uncle = grandparent->left;
// Case 1: Uncle is RED → Recoloring
if (uncle != NULL && uncle->color == RED) {
grandparent->color = RED;
parent->color = BLACK;
uncle->color = BLACK;
pt = grandparent;
}
else {
// Case 2: Node is left child → Right Rotation
if (pt == parent->left) {
pt = parent;
root = rightRotate(root, pt);
parent = pt->parent;
}
// Case 3: Node is right child → Left Rotation
parent->color = BLACK;
grandparent->color = RED;
root = leftRotate(root, grandparent);
}
}
}
// Root must always be black
root->color = BLACK;
return root;
}
// Standard BST insert + fix RBT violations
Node* insert(Node* root, int data) {
Node* pt = createNode(data);
Node* y = NULL;
Node* x = root;
// Standard BST insert
while (x != NULL) {
y = x;
if (pt->data < x->data)
x = x->left;
else
x = x->right;
}
pt->parent = y;
if (y == NULL)
root = pt;
else if (pt->data < y->data)
y->left = pt;
else
y->right = pt;
// Fix Red-Black Tree violations
root = fixViolation(root, pt);
return root;
}
// Inorder traversal to display tree contents
void inorder(Node* root) {
if (root == NULL)
return;
inorder(root->left);
printf("%d [%s] ", root->data, (root->color == RED) ? "R" : "B");
inorder(root->right);
}
int main() {
Node* root = NULL;
int arr[] = {10, 20, 30, 15, 25};
int n = sizeof(arr)/sizeof(arr[0]);
for (int i = 0; i < n; i++) {
root = insert(root, arr[i]);
}
printf("Inorder traversal of Red-Black Tree:\n");
inorder(root);
return 0;
}
Output
Inorder traversal of Red-Black Tree:
10 [B] 15 [R] 20 [B] 25 [R] 30 [B]
Working of R B Tree with Example
Problem:
Insert the following elements into an initially empty Red-Black Tree:
[10, 20, 30, 15]
✅ Step-by-Step Execution:
🔢 Inserting 10:
- Tree is empty → Insert 10 as the root.
- Root must always be black, so we color 10 as black.
10(B)
✅ No violations → Tree is valid.
🔢 Inserting 20:
- 20 > 10 → Insert 20 as right child of 10.
- By default, new node is red.
10(B)
\
20(R)
✅ No violation (red node under black parent) → Tree is valid.
🔢 Inserting 30:
- 30 > 10 → right of 10
- 30 > 20 → right of 20
- Insert 30 as right child of 20, color it red.
10(B)
\
20(R)
\
30(R)
🚨 Violation Detected!
20 and 30 are both red → violates Rule #4 (no two consecutive red nodes).
🔁 Fixing the Tree:
Parent (20) is red, and Uncle (left of 10) is NIL → Black.
Case: Right-Right situation (Node is right child of right parent)
✅ Action: Left Rotate at 10 and Recolor
- Left Rotate 10 → 20 becomes new root.
- Recolor:
- 20 → Black
- 10 → Red
20(B)
/ \
10(R) 30(R)
✅ All rules satisfied.
🔢 Inserting 15:
- 15 < 20 → left of 20
- 15 > 10 → right of 10
- Insert 15 as right child of 10, color it red.
20(B)
/ \
10(R) 30(R)
\
15(R)
🚨 Violation Detected!
10 and 15 are both red → violates rule.
🔁 Fixing the Tree:
- Parent = 10 (red)
- Uncle = 30 (red)
Case: Red Uncle → Use Recoloring
✅ Recolor:
- 10 → Black
- 30 → Black
- 20 → Red (was black)
20(R)
/ \
10(B) 30(B)
\
15(R)
But now root is red ❌ violates Rule #2 → root must be black.
✅ Fix: Recolor root back to black
20(B)
/ \
10(B) 30(B)
\
15(R)
✅ All properties satisfied.
✅ Final Red-Black Tree After Inserting [10, 20, 30, 15]:
20(B)
/ \
10(B) 30(B)
\
15(R)
What Just Happened?
- Rotations occurred only once (Left Rotate at 10)
- Recoloring used twice to handle red-red violations
- Tree stayed balanced with height = 3
- Time complexity remained O(log n)
Learning Summary:
Step | Operation | Violation | Fix |
---|---|---|---|
10 | Insert | None | Root Black |
20 | Insert | None | – |
30 | Insert | Red-Red (20, 30) | Left Rotate at 10, Recolor |
15 | Insert | Red-Red (10, 15) | Recolor 10, 30, and 20 |
Red-Black Tree Time and Space Complexity
Operation | Time Complexity | Space Complexity |
---|---|---|
Search | O(log n) | O(n) |
Insertion | O(log n) | O(n) |
Deletion | O(log n) | O(n) |
Traversal (Inorder, Preorder, Postorder) | O(n) | O(n) |
Why Time Complexity is O(log n)?
Red-Black Tree is a self-balancing binary search tree. Because of the color and rotation rules, the tree stays balanced — meaning its height is always logarithmic in terms of the number of nodes (n).
Even in the worst case:
- It won’t degrade to a linear structure (like a simple unbalanced BST).
- The height is always at most 2 × log(n + 1).
Thus, search, insert, and delete operations only go down the height of the tree → O(log n).
Space Complexity
- Space per node: Constant (each node has color, value, and two child references).
- Total space: O(n) for
n
nodes. - If recursion is used (e.g., in deletion or traversal), then the call stack might go up to O(log n) depth.
Valid Parent-Child Color Combinations in a Red-Black Tree:
Parent Color | Child Color | Valid? |
---|---|---|
Black | Black | ✅ Yes |
Black | Red | ✅ Yes |
Red | Black | ✅ Yes |
Red | Red | ❌ No — violates Red-Black Property 4 |
🌐 Real-Time Use Cases of R B Tree
- Cloud Databases: Used to maintain index trees for fast key-based lookup
- Mobile OS: For app scheduling and state management
- Embedded Systems: Efficient storage of time-critical or sorted configurations
Advantages of Red-Black Tree
- 🔄 Self-Balancing: Ensures tree height stays within O(log n) without excessive rotations.
- ⚡ Efficient Operations: Insert, delete, and search operations all take O(log n) time.
- 🧠 Low Overhead: Requires fewer rotations compared to AVL trees in insertion-heavy scenarios.
- 🧩 Consistent Performance: Even in the worst case, performance is predictable—important for real-time systems.
- 💻 Widely Used in Libraries: STL’s
map
andset
in C++, Java’s TreeMap are based on RBTs. - 🔧 Scalable: Works well with dynamic data where frequent insertions and deletions occur.
- 🧷 Memory Efficient: Requires no additional balancing factor as in AVL trees (uses just one color bit).
Disadvantages of Red-Black Tree
- Complex Implementation:
🔧 Red-Black Trees are harder to understand and implement compared to simple Binary Search Trees (BST) or arrays. Managing color rules, rotations, and rebalancing can be tricky. - More Code Overhead:
🧱 Writing insert and delete functions in Red-Black Trees requires more lines of code because of multiple conditions and balancing cases. - Slower than AVL in Some Cases:
🐢 Although both are balanced trees, AVL trees are more strictly balanced, so they can be slightly faster for search-heavy operations. - Not Always Space-Efficient:
🧠 Each node needs extra memory to store the color bit, which slightly increases memory usage compared to a regular BST. - Harder to Debug:
🧩 If something goes wrong in your Red-Black Tree logic (like rotation or coloring), it’s harder to find and fix the bug compared to simpler data structures.
❓FAQs on Red-Black Tree (RBT)
Q1. What is a Red-Black Tree in simple words?
A Red-Black Tree is a type of Binary Search Tree that keeps itself balanced using color rules (red and black). This helps in keeping search, insert, and delete operations fast — even when the number of elements is large.
Q2. Why do we use Red-Black Trees?
We use Red-Black Trees to:
- Keep data sorted
- Ensure fast performance (O(log n)) for operations
- Avoid unbalanced trees, which can slow down performance
Q3. What are the main properties of a Red-Black Tree?
- Every node is either red or black.
- Root is always black.
- No two red nodes appear in a row.
- Every path from a node to NULL has the same number of black nodes.
- All leaves (NULL) are black.
Q4. What are the advantages of Red-Black Trees?
- Self-balancing
- Fast operations (search, insert, delete in O(log n))
- Used in real-world systems (e.g., Java TreeMap, Linux Kernel)
Q5. What are the disadvantages of Red-Black Trees?
- Complex to implement
- Harder to debug
- Slightly slower than AVL trees for search-heavy tasks
Q6. Where are Red-Black Trees used in real life?
- In C++ STL (
std::map
,std::set
) - In Java (
TreeMap
,TreeSet
) - In Linux kernel (task scheduling and memory management)
- In database indexing systems
Q7. Is Red-Black Tree faster than AVL Tree?
It depends:
- Red-Black Trees are better for insertion/deletion-heavy operations.
- AVL Trees are better for search-heavy operations because they are more strictly balanced.
Q8. What is the time complexity of Red-Black Tree operations?
- Search: O(log n)
- Insert: O(log n)
- Delete: O(log n)