Back to Data Structures & Algorithms
2026-04-067 min read

Deletion From a Red-Black Tree (Data Structures & Algorithms)

Learn Deletion From a Red-Black Tree (Data Structures & Algorithms) step by step with clear examples and exercises.

Why This Matters

Deleting a node from a Red-Black Tree is crucial for maintaining its balance and efficiency. This operation ensures that the tree remains a self-balancing binary search tree, with an average time complexity of O(log n) for insertion, deletion, and search operations. Understanding how to delete a node from a Red-Black Tree is essential for mastering data structures and algorithms, as it helps you solve real-world problems and prepare for technical interviews.

Prerequisites

Before diving into deletion in Red-Black Trees, you should be familiar with the following:

  1. Basic Python concepts (variables, functions, loops, conditionals)
  2. Binary Search Trees (BST) and their operations (insertion, search, traversal)
  3. Understanding of recursion
  4. Familiarity with Red-Black Tree properties and insertion process
  5. Knowledge of Python classes and object-oriented programming concepts
  6. Comprehension of the __init__, parent, and other helper functions used in the example code
  7. Basic understanding of tree traversal (inorder, preorder, postorder)
  8. Understanding of Python's built-in data structures like lists and dictionaries
  9. Familiarity with Big O notation and time complexity analysis
  10. Knowledge of Python's error handling mechanisms (try/except blocks)

Core Concept

A Red-Black Tree is a binary search tree with the following additional properties:

  1. Every node has a color (either red or black)
  2. The root, empty tree, and all leaves are black
  3. Each node with two red children is black
  4. For each node, all paths from the node to the leaf descendants have the same number of black nodes

Deleting a node in a Red-Black Tree involves four cases:

  1. Deleting a leaf (black or red)
  2. Deleting a node with one red child
  3. Deleting a node with two black children
  4. Deleting a node with two red children

Case 1: Deleting a Leaf (Black or Red)

  • A black leaf can be deleted directly, and its parent's color changes to red if it has become empty.
  • A red leaf can be replaced by its sibling, maintaining the tree's balance.

Case 2: Deleting a Node with One Red Child

  • The red child is promoted to black, and the parent becomes red.
  • If the parent is now violating any property, we recursively apply the appropriate balancing operation (case 3 or case 4).

Case 3: Deleting a Node with Two Black Children

  • Perform a left rotation on the node to make one of its children the new root.
  • If the new root's sibling is red, perform a right rotation and color changes to balance the tree (case 2).

Case 4: Deleting a Node with Two Red Children

  • Perform a left rotation on the node to make one of its children the new root.
  • If the new root's sibling is black, change both siblings and their parent to red, making the parent's parent the problematic node (case 3 or case 4).

Worked Example

Let's delete the value 17 from the following Red-Black Tree:

class Node:
def __init__(self, key, color):
self.key = key
self.left = None
self.right = None
self.color = color
self.parent = None

def insert(root, key):
if root is None:
return Node(key, 'red')
else:
if key < root.key:
root.left = root.left.insert(root.left, key)
root.left.parent = root
elif key > root.key:
root.right = root.right.insert(root.right, key)
root.right.parent = root
if is_red(root.left) and is_red(root.right):
return balance(root)
return root

def balance(node):
if node is None:
return None

if is_black(node.right.left) and is_black(node.right.right):
node = rotate_left(node)

if is_red(node.left):
node.left = rotate_left(node.left)
node = rotate_right(node)

if is_black(node.left) and is_black(node.right):
node.color = 'red'
return node

if height(node.left) > height(node.right):
if height(node.left.left) > height(node.left.right):
node = rotate_right(node)
node = rotate_left(node)
else:
if height(node.right.left) > height(node.right.right):
node = rotate_left(node)
node = rotate_right(node)
else:
if height(node.right.left) > height(node.right.right):
node = rotate_left(node)
node = rotate_right(node)

return node

def rotate_left(self, node):
y = node.right
T3 = y.left
y.left = node
node.parent = y
node.right = T3

if T3 is not None:
T3.parent = node

return y

def rotate_right(self, node):
y = node.left
T2 = y.right
y.right = node
node.parent = y
node.left = T2

if T2 is not None:
T2.parent = node

return y

def is_red(node):
return node and node.color == 'red'

def is_black(node):
return node and node.color == 'black'

def height(node):
if node is None:
return 0
else:
left_height = height(node.left)
right_height = height(node.right)
return max(left_height, right_height) + 1

def delete(root, key):
if root is None:
return root

if key < root.key:
root.left = delete(root.left, key)
elif key > root.key:
root.right = delete(root.right, key)

if root.right is None:
return root.left

if is_black(root.left) and is_red(root.right):
root.color = 'red'
root.right = balance(root.right)

if root.right is not None and (is_black(root.right.left) or is_black(root.right.right)):
root = move_down(root)

return balance(root)

def move_down(self, node):
if is_red(node.left) and is_black(node.right):
node.left, node.right = node.right, node.left
node.color = 'red'
return balance(node)

if is_black(node.left) and is_red(node.right):
if is_black(node.right.left):
node.right = rotate_left(node.right)
node.color = 'red'
node.right = balance(node.right)

if is_black(node.left) and is_black(node.right):
if is_black(node.left.left) and is_black(node.left.right):
node = rotate_right(node)
node = rotate_left(node)
else:
if is_black(node.right.left) and is_black(node.right.right):
node = rotate_left(node)
node = rotate_right(node)
else:
if is_black(node.right.left) and is_black(node.right.right):
node = rotate_left(node)
node = rotate_right(node)

return node

def inorder_traversal(node):
if node is not None:
inorder_traversal(node.left)
print(node.key, end=' ')
inorder_traversal(node.right)

tree = Node(10, 'black')
insert(tree, 2)
insert(tree, 4)
insert(tree, 6)
insert(tree, 8)
insert(tree, 12)
insert(tree, 14)
insert(tree, 17)

print("Original Tree:")
inorder_traversal(tree)

delete(tree, 17)
print("\nTree after deleting 17:")
inorder_traversal(tree)

Common Mistakes

  1. Forgetting to check if the node being deleted is a leaf or has one red child.
  2. Not properly handling cases when the deleted node has two black children (case 3 and case 4).
  3. Failing to update the parent of the replaced sibling in case 2.
  4. Forgetting to balance the tree after performing rotations (cases 3 and 4).
  5. Not returning the new root after deleting a node.
  6. Neglecting to handle cases when the deleted node is the root or has only one child.
  7. Misunderstanding the order of operations during balancing, leading to incorrect results.
  8. Failing to maintain the Red-Black Tree properties throughout the deletion process.
  9. Using an inefficient implementation that does not take advantage of the tree's self-balancing property.
  10. Not properly implementing the helper functions (rotate_left, rotate_right, move_down, etc.) required for the deletion algorithm.
  11. Failing to handle edge cases like a single node or an empty tree during insertion and deletion operations.
  12. Neglecting to update the height of nodes after rotations or deletions.
  13. Implementing inefficient search algorithms that do not take advantage of the Red-Black Tree's properties.

Practice Questions

  1. Write a function to search for a given key in a Red-Black Tree using recursive and iterative approaches.
  2. Implement the inorder_traversal function using preorder, postorder, and breadth-first traversals.
  3. Given the following Red-Black Tree, delete the nodes with keys 7 and 15:
class Node:
def __init__(self, key, color):
self.key = key
self.left = None
self.right = None
self.color = color
self.parent = None

... (insert, balance, height, delete functions)

tree = Node(5, 'black')

insert(tree, 3)

insert(tree, 7)

insert(tree, 10)

insert(tree, 15)

insert(tree, 20)

insert(tree, 25)

print("Original Tree:")

inorder_traversal(tree)

delete(tree, 7)

delete(tree, 15)

print("\nTree after deleting 7 and 15:")

inorder_traversal(tree)

FAQ

What happens if we delete a root node in a Red-Black Tree?

  • If the root is red, it can be deleted directly. If it's black, its successor or predecessor will replace it, and the new root may need balancing operations.

Can a Red-Black Tree have two red siblings?

  • No, because having two red siblings would violate the property that every path from the root to a leaf has the same number of black nodes.

Why do we need to balance the tree after performing rotations in case 3 or case 4?

  • Balancing ensures that the Red-Black Tree properties are maintained, which guarantees efficient insertion, deletion, and search operations.

Can a leaf node be red in a Red-Black Tree?

  • Yes, a leaf node can be either black or red.

What is the time complexity of deleting a node from a Red-Black Tree?

  • The average time complexity for deletion in a Red-Black Tree is O(log n). However, in the worst case, it could take O(n) due to an unbalanced tree structure or improper implementation.
Deletion From a Red-Black Tree (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn