A red-black tree is a type of self-balancing binary tree. This Answer covers deletion in a red-black tree using Python.
Note: To read more about red-black trees, visit here.
Deletion in a red-black tree is similar to a BST, except for one added step. If, after deletion, a red-black property is disrupted, the tree has to be recolored or rotated.
The process is as follows:
First, we find the node that we want to delete.
In case it is a leaf node, we just replace it with None
. Otherwise, we replace it with a leaf node, which must be a child with the minimum value. Then, we set it to None
.
If the color properties are violated, we rebalance and recolor the tree.
Let's look at some code to see how it works.
class Node:def __init__(self, value, color=RED):self.value = valueself.left = Noneself.right = Noneself.parent = Noneself.color = colorclass RedBlackTree:def __init__(self):self.root = Noneself.none = Node(0, BLACK)def _min(self, node):while node.left != self.none:node = node.leftreturn nodedef delete(self, val):return self._delete(self.root, val)def _delete(self, node, val):temp = self.nonewhile node != self.none:if node.value == val:temp = nodeif node.value <= val:node = node.rightelse:node = node.leftif temp == self.none:return Falsetemp2 = temptemp2_original_color = temp2.colorif temp.left == self.none:temp3 = temp.rightself._rbt ( temp , temp.right )elif (temp.right == self.none):temp3 = temp.leftself._rbt ( temp , temp.left )else:temp2 = self.minimum ( temp.right )temp2_original_color = temp2.colortemp3 = temp2.rightif temp2.parent == temp:temp3.parent = temp2else:self._rbt ( temp2 , temp2.right )temp2.right = temp.righttemp2.right.parent = temp2self._rbt ( temp , temp2 )temp2.left = temp.lefttemp2.left.parent = temp2temp2.color = temp.colorif temp2_original_color == BLACK:self._fixDelete( temp3 )def _rbt(self, x, y):if not x.parent:self.root = yelif x == x.parent.left:x.parent.left = yelse:x.parent.right = yy.parent = x.parentdef _fixDelete(self, node):while node != self.root and node.color == BLACK:if node == node.parent.left:temp = node.parent.rightif temp.color == RED:temp.color = BLACKnode.parent.color = REDself.leftRotate(node.parent)temp = node.parent.rightif temp.left.color == BLACK and temp.right.color == BLACK:temp.color = REDnode = node.parentelse:if temp.right.color == BLACK:temp.left.color = BLACKtemp.color = REDself.rightRotate(temp)temp = node.parent.righttemp.color = node.parent.colornode.parent.color = BLACKtemp.right.color = BLACKself.leftRotate(node.parent)node = self.rootelse:temp = node.parent.leftif temp.color == RED:temp.color = BLACKnode.parent.color = REDself.rightRotate(node.parent)temp = node.parent.leftif temp.right.color == BLACK and temp.right.color == BLACK:temp.color = REDnode = node.parentelse:if temp.left.color == BLACK:temp.right.color = BLACKtemp.color = REDself.leftRotate(temp)temp = node.parent.lefttemp.color = node.parent.colornode.parent.color = BLACKtemp.left.color = BLACKself.rightRotate(node.parent)node = node.rootnode.color = BLACKdef leftRotate(self, node):right_child = node.rightnode.right = right_child.leftif right_child.left != self.none:right_child.left.parent = nodeif not node.parent:self.root = right_childelif node.parent.left == node:node.parent.left = right_childelse:node.parent.right = right_childright_child.parent = node.parentright_child.left = nodenode.parent = right_childdef rightRotate(self, node):left_child = node.leftnode.left = left_child.rightif left_child.right != self.none:left_child.right.parent = nodeif not node.parent:self.root = left_childelif node.parent.left == node:node.parent.left = left_childelse:node.parent.right = left_childleft_child.parent = node.parentleft_child.right = nodenode.parent = left_childtree = RedBlackTree()tree.root = Node(10, BLACK)tree.root.left = Node(5, BLACK)tree.root.left.parent = tree.roottree.root.right = Node(20, BLACK)tree.root.right.parent = tree.roottree.root.left.left = Node(1, BLACK)tree.root.left.left.parent = tree.root.lefttree.root.left.right = Node(7, BLACK)tree.root.left.right.parent = tree.root.lefttree.root.right.left = Node(15, BLACK)tree.root.right.left.parent = tree.root.righttree.root.right.right = Node(30, BLACK)tree.root.right.right.parent = tree.root.righttree.root.right.right.right = tree.nonetree.root.right.right.left = tree.nonetree.root.right.left.right = tree.nonetree.root.right.left.left = tree.nonetree.root.left.right.right = tree.nonetree.root.left.right.left = tree.nonetree.root.left.left.left = tree.nonetree.root.left.left.right = tree.nonetree.delete(7) # delete the treeprint(" ", tree.root.value, tree.root.color)print(" / \\")print(" ", tree.root.left.value, tree.root.left.color, " ", tree.root.right.value, tree.root.right.color)print(" / / \\")print("", tree.root.left.left.value, tree.root.left.left.color, " ", tree.root.right.left.value, tree.root.right.left.color, " ", tree.root.right.right.value, tree.root.right.right.color)
Lines 1–7: We define a Node
class that stores one node of the red-black tree.
Lines 19–20: We define a delete()
function that calls the _delete()
helper function.
Lines 22–60: The _delete()
function first goes through the tree to find the node. It then deletes the node and checks if any properties are violated. If they are, it calls the _fixDelete()
function.
Lines 71–115: The fixDelete()
function rebalances and recolors the tree. It starts at the deleted node, and then goes up to the root until the tree is balanced again.
Lines 151–180: We create a tree
, call the delete()
function on it, and print the resulting red-black tree.