A red-black tree is a binary search tree in which each node, 
,
has a color which is either red or black.  Red is
represented by the value 0 and black by the value 
.
  class RedBlackNode : public BSTNode<Node, T> {
    friend class RedBlackTree<Node, T>;
    char color;
  };
  int red = 0;
  int black = 1;
Before and after any operation on a red-black tree, the following two properties are satisfied. Each property is defined both in terms of the colors red and black, and in terms of the numeric values 0 and 1.
 
  
 | 
At first it might seem surprising that a red-black tree can be efficiently updated to maintain the black-height and no-red-edge properties, and it seems unusual to even consider these as useful properties. However, red-black trees were designed to be an efficient simulation of 2-4 trees as binary trees.
Refer to Figure 9.5.
Consider any red-black tree, 
, having 
 nodes and perform the
following transformation: Remove each red node 
 and connect 
's two
children directly to the (black) parent of 
.  After this transformation
we are left with a tree 
 having only black nodes.
Every internal node in 
 has 2, 3, or 4 children: A black node that
started out with two black children will still have two black children
after this transformation.  A black node that started out with one red
and one black child will have three children after this transformation.
A black node that started out with two red children will have 4 children
after this transformation.  Furthermore, the black-height property now
guarantees that every root-to-leaf path in 
 has the same length.
In other words, 
 is a 2-4 tree!
The 2-4 tree 
 has 
 leaves that correspond to the 
external nodes of the red-black tree.  Therefore, this tree has height
. Now, every root to leaf path in the 2-4 tree corresponds
to a path from the root of the red-black tree 
 to an external node.
The first and last node in this path are black and at most one out of
every two internal nodes is red, so this path has at most 
black nodes and at most 
 red nodes.  Therefore, the longest path from the root to any internal node in 
 is at most
Now that we have seen the relationship between 2-4 trees and red-black trees, it is not hard to believe that we can efficiently maintain a red-black tree while adding and removing elements.
We have already seen that adding an element in a 
can be done by adding a new leaf.  Therefore, to implement 
 in a
red-black tree we need a method of simulating splitting a degree 5 node
in a 2-4 tree.  A degree 5 node is represented by a black node that has
two red children one of which also has a red child. We can ``split''
this node by coloring it red and coloring its two children black.
An example of this is shown in Figure 9.6.
  | 
Similarly, implementing 
 requires a method of merging two
nodes and borrowing a child from a sibling.  Merging two nodes is the
inverse of a split (shown in Figure 9.6), and involves coloring
two (black) siblings red and coloring their (red) parent black.
Borrowing from a sibling is the most complicated of the procedures and involves both rotations and recoloring of nodes.
Of course, during all of this we must still maintain the no-red-edge property and the black-height property. While it is no longer surprising that this can be done, there are a large number of cases that have to be considered if we try to do a direct simulation of a 2-4 tree by a red-black tree. At some point, it just becomes simpler to forget about the underlying 2-4 tree and work directly towards maintaining the red-black tree properties.
There is no single definition of a red-black tree.  Rather,
there are a family of structures that manage to maintain the
black-height and no-red-edge properties during 
 and 
operations. Different structures go about it in different ways.  Here, we
implement a data structure that we call a 
.  This structure
implements a particular variant of red-black trees that satisfies an
additional property:
Note that the red-black tree shown in Figure 9.4 does not satisfy the left-leaning property; it is violated by the parent of the red node in the rightmost path.
The reason for maintaining the left-leaning property is that it reduces
the number of cases encountered when updating the tree during 
and 
 operations.  In terms of 2-4 trees, it implies that
every 2-4 tree has a unique representation:  A node of degree 2 becomes
a black node with 2 black children.  A node of degree 3 becomes a black
node whose left child is red and whose right child is black.  A node of
degree 4 becomes a black node with two red children.
Before we describe the implementation of 
 and 
 in
detail, we first present some simple subroutines used by these methods
that are illustrated in Figure 9.7.  The first two
subroutines are for manipulating colors while preserving the black-height
property. The 
 method takes as input a black node 
that has two red children and colors 
 red and its two children black.
The 
 method reverses this operation:
  void pushBlack(Node *u) {
    u->color--;
    u->left->color++;
    u->right->color++;
  }
  void pullBlack(Node *u) {
    u->color++;
    u->left->color--;
    u->right->color--;
  }
The 
 method swaps the colors of 
 and 
 and
then performs a left rotation at 
.  This reverses the colors
of these two nodes as well as their parent-child relationship:
  void flipLeft(Node *u) {
    swapColors(u, u->right);
    rotateLeft(u);
  }
The 
  void flipRight(Node *u) {
    swapColors(u, u->left);
    rotateRight(u);
  }
To implement 
 in a 
, we perform a standard
 insertion, which adds a new leaf, 
, with 
and set 
.  Note that this does not change the black
height of any node, so it does not violate the black-height property.
It may, however, violate the left-leaning property (if 
 is the
right child of its parent) and it may violate the no-red-edge property
(if 
's parent is 
).  To restore these properties, we call the
method 
.
  bool add(T x) {
    Node *u = new Node();
    u->left = u->right = u->parent = nil;
    u->x = x;
    u->color = red;
    bool added = BinarySearchTree<Node,T>::add(u);
    if (added)
      addFixup(u);
    return added;
  }
The 
 method, illustrated in Figure 9.8, takes
as input a node 
 whose color is red and which may be violating the
no-red-edge property and/or the left-leaning property.  The following
discussion is probably impossible to follow without referring to
Figure 9.8 or recreating it on a piece of paper.  Indeed, the
reader may wish to study this figure before continuing.
If 
 is the root of the tree, then we can color 
 black and this
restores both properties.  If 
's sibling is also red, then 
's
parent must be black, so both the left-leaning and no-red-edge properties
already hold.
Otherwise, we first determine if 
's parent, 
, violates the
left-leaning property and, if so, perform a 
 operation and
set 
.  This leaves us in a well-defined state:  
 is the left
child of its parent, 
, so 
 now satisfies the left-leaning property.
All that remains is to ensure the no-red-edge property at 
.  
We only have to worry about the case where 
 is red, since otherwise
 already satisfies the no-red-edge property.
Since we are not done yet, 
 is red and 
 is red.  The no-red-edge
property (which is only violated by 
 and not by 
) implies that
's grandparent 
 exists and is black.  If 
's right child is red,
then the left-leaning property ensures that both 
's children are red,
and a call to 
 makes 
 red and 
 black.  This restores
the no-red-edge property at 
, but may cause it to be violated at 
,
so the whole process starts over with 
.
If 
's right child is black, then a call to 
 makes
 the (black) parent of 
 and gives 
 two red children, 
 and
. This ensures that 
 satisfies the no-red-edge property and 
satisfies the left-leaning property.  In this case we can stop.
  void addFixup(Node *u) {
    while (u->color == red) {
      if (u == r) { // u is the root - done
        u->color = black;
        return;
      }
      Node *w = u->parent;
      if (w->left->color == black) { // ensure left-leaning
        flipLeft(w);
        u = w;
        w = u->parent;
      }
      if (w->color == black)
        return; // no red-red edge = done
      Node *g = w->parent; // grandparent of u
      if (g->right->color == black) {
        flipRight(g);
        return;
      } else {
        pushBlack(g);
        u = g;
      }
    }
  }
The 
 method takes constant time per iteration and each
iteration either finishes or moves 
 closer to the root.  This implies
that the 
 method finishes after 
 iterations
in 
 time.
The 
 operation in a 
 tree is the most complicated
operation to implement, and this is true of all known implementations.
Like 
 in a BinarySearchTree, this operation boils
down to finding a node 
 with only one child, 
, and splicing 
out of the tree by having 
 adopt 
.
The problem with this is that, if 
 is black, then the black-height
property will now be violated at 
.  We get around this
problem, temporarily, by adding 
 to 
.  Of course, this
introduces two other problems:  (1) 
 and 
 both started out black,
then 
 (double black), which is an invalid color.
If 
 was red, then it is replaced by a black node 
, which may
violate the left-leaning property at 
.  Both of these problems
are resolved with a call to the 
 method.
  bool remove(T x) {
    Node *u = findLast(x);
    if (u == nil || compare(u->x, x) != 0)
      return false;
    Node *w = u->right;
    if (w == nil) {
      w = u;
      u = w->left;
    } else {
      while (w->left != nil)
        w = w->left;
      u->x = w->x;
      u = w->right;
    }
    splice(w);
    u->color += w->color;
    u->parent = w->parent;
    delete w;
    removeFixup(u);
    return true;
  }
The 
 method takes as input a node 
 whose color is black
(1) or double-black (2).  If 
 is double-black, then 
performs a series of rotations and recoloring operations that move the
double-black node up the tree until it can be gotten rid of.  During this
process, the node 
 changes until, at the end of this process, 
refers to the root of the subtree that has been changed.  The root of
this subtree may have changed color.  In particular, it may have gone
from red to black, so the 
 method finishes by checking
if 
's parent violates the left-leaning property and, if so, fixes it.
  void removeFixup(Node *u) {
    while (u->color > black) {
      if (u == r) {
        u->color = black;
      } else if (u->parent->left->color == red) {
        u = removeFixupCase1(u);
      } else if (u == u->parent->left) {
        u = removeFixupCase2(u);
      } else {
        u = removeFixupCase3(u);
      }
    }
    if (u != r) { // restore left-leaning property, if necessary
      Node *w = u->parent;
      if (w->right->color == red && w->left->color == black) {
        flipLeft(w);
      }
    }
  }
The 
 method is illustrated in Figure 9.9.
Again, the following text will be very difficult, if not impossible,
to follow without referring constantly to Figure 9.9.
Each iteration of the loop in 
 processes the double-black node 
 based on one of four cases.
Case 0: 
 is the root.  This is the easiest case to treat.  We recolor 
 to be black and this does not violate any of the red-black tree properties.
Case 1: 
's sibling, 
, is red.  In this case, 
's sibling is the
left child of its parent, 
 (by the left-leaning property).  We perform
a right-flip at 
 and then proceed to the next iteration.  Note that
this causes 
's parent to violate the left-leaning property and it
causes the depth of 
 to increase.  However, it also implies that the
next iteration will be in Case 3 with 
 colored red.  When examining
Case 3, below, we will see that this means the process will stop during
the next iteration.
  Node* removeFixupCase1(Node *u) {
    flipRight(u->parent);
    return u;
  }
Case 2: 
's sibling, 
, is black and 
 is the left child of its
parent, 
.  In this case, we call 
, making 
 black,
 red, and darkening the color of 
 to black or double-black.
At this point, 
 does not satisfy the left-leaning property, so we
call 
 to fix this.
At this point, 
 is red and 
 is the root of the subtree we started
with.  We need to check if 
 causes no-red-edge property to be violated.
We do this by inspecting 
's right child, 
.  If 
 is black,
then 
 satisfies the no-red-edge property and we can continue to the
next iteration with 
=
.
Otherwise (
 is red), both the no-red-edge property and the left-leaning
property are violated at 
 and 
, respectively.  A call to
 restores the left-leaning property, but the no-red-edge
property is still violated.  At this point, 
 is the left child of
 and 
 is the left child of 
, 
 and 
 are both red and 
is black or double-black.  A 
  makes 
 the parent of
both 
 and 
.  Following this up by a 
 makes both 
and 
 black and sets the color of 
 back to the original color of 
.
At this point, there is no more double-black node and the no-red-edge and
black-height properties are reestablished.  The only possible problem
that remains is that the right child of 
 may be red, in which case
the left-leaning property is violated.  We check this and perform a
 to correct it if necessary.
  Node* removeFixupCase2(Node *u) {
    Node *w = u->parent;
    Node *v = w->right;
    pullBlack(w); // w->left
    flipLeft(w); // w is now red
    Node *q = w->right;
    if (q->color == red) { // q-w is red-red
      rotateLeft(w);
      flipRight(v);
      pushBlack(q);
      if (v->right->color == red)
        flipLeft(v);
      return q;
    } else {
      return v;
    }
  }
Case 3: 
's sibling is black and 
 is the right child of its parent,
.  This case is symmetric to Case 2 and is handled mostly the same way.
The only differences come from the fact that the left-leaning property
is asymmetric, so it requires different handling.
As before, we begin with a call to 
, which makes 
 red
and 
 black.  A call to 
 promotes 
 to the root of
the subtree.  At this point 
 is red, and the code branches two ways
depending on the color of 
's left child, 
.
If 
 is red, then the code finishes up exactly the same way that
Case 2 finishes up, but is even simpler since there is no danger of 
not satisfying the left-leaning property.
The more complicated case occurs when 
 is black.  In this case,
we examine the color if 
's left child.  If it is red, then 
 has
two red children and its extra black can be pushed down with a call to
.  At this point, 
 now has 
's original color and we
are done.
If 
's left child is black then 
 violates the left-leaning property
and we restore this with a call to 
.  The next iteration
of 
 then continues with 
.
  Node* removeFixupCase3(Node *u) {
    Node *w = u->parent;
    Node *v = w->left;
    pullBlack(w);
    flipRight(w);            // w is now red
    Node *q = w->left;
    if (q->color == red) {    // q-w is red-red
      rotateRight(w);
      flipLeft(v);
      pushBlack(q);
      return q;
    } else {
      if (v->left->color == red) {
        pushBlack(v);   // both v's children are red
        return v;
      } else {            // ensure left-leaning
        flipLeft(v);
        return w;
      }
    }
  }
Each iteration of 
 takes constant time.  Cases 2 and 3
either finish or move 
 closer to the root of the tree.  Case 0 (where
 is the root) always terminates and Case 1 leads immediately to Case 3,
which also terminates.  Since the height of the tree is at most 
, we conclude that there are at most 
 iterations of
 so 
 runs in 
 time.
opendatastructures.org