The read-only operations, such as search or tree traversal, on a red–black tree require no modification from those used for
binary search trees, because every red–black tree is a special case of a simple binary search tree. However, the immediate result of an insertion or removal may violate the properties of a red–black tree, the restoration of which is called
rebalancing so that red–black trees become self-balancing. Rebalancing (i.e. color changes) has a worst-case time complexity of O(\log n) and average of O(1), (two for insertion). This is an example implementation of insert and remove in
C. Below are the data structures and the rotate_subtree helper function used in the insert and remove examples. typedef enum Color: char { BLACK, RED } Color; typedef enum Direction: char { LEFT, RIGHT } Direction; // red-black tree node typedef struct Node { struct Node* parent; // null for the root node union { // Union so we can use ->left/->right or ->child[0]/->child[1] struct { struct Node* left; struct Node* right; }; struct Node* child[2]; }; Color color; int key; } Node; typedef struct { struct Node* root; } Tree; static Direction direction(const Node* N) { return N == N->parent->right ? RIGHT : LEFT; } Node* rotate_subtree(Tree* tree, Node* sub, Direction dir) { Node* sub_parent = sub->parent; Node* new_root = sub->child[1 - dir]; // 1 - dir is the opposite direction Node* new_child = new_root->child[dir]; sub->child[1 - dir] = new_child; if (new_child) { new_child->parent = sub; } new_root->child[dir] = sub; new_root->parent = sub_parent; sub->parent = new_root; if (sub_parent) { sub_parent->child[sub == sub_parent->right] = new_root; } else { tree->root = new_root; } return new_root; }
Notes to the sample code and diagrams of insertion and removal The proposal breaks down both insertion and removal (not mentioning some very simple cases) into six constellations of nodes, edges, and colors, which are called cases. The proposal contains, for both insertion and removal, exactly one case that advances one black level closer to the root and loops, the other five cases rebalance the tree of their own. The more complicated cases are pictured in a diagram. • symbolises a red node and a (non-NULL) black node (of black height ≥ 1), symbolises the color red or black of a non-NULL node, but the same color throughout the same diagram. NULL nodes are not represented in the diagrams. • The variable
N denotes the current node, which is labeled N or N in the diagrams. • A diagram contains three columns and two to four actions. The left column shows the first iteration, the right column the higher iterations, the middle column shows the segmentation of a case into its different actions. • The action "entry" shows the constellation of nodes with their colors which defines a case and mostly violates some of the
requirements.A blue border rings the current node
N and the other nodes are labeled according to their relation to
N. • If a
rotation is considered useful, this is pictured in the next action, which is labeled "rotation". • If some recoloring is considered useful, this is pictured in the next action, which is labeled "color". • If there is still some need to repair, the cases make use of code of other cases and this after a reassignment of the current node
N, which then again carries a blue ring and relative to which other nodes may have to be reassigned also. This action is labeled "reassign".For both, insert and delete, there is (exactly) one case which iterates one black level closer to the root; then the reassigned constellation satisfies the respective loop invariant. • A possibly numbered triangle with a black circle atop represents a red–black subtree (connected to its parent according to
requirement 3) with a black height equal to the iteration level minus one, i.e. zero in the first iteration. Its root may be red or black.A possibly numbered triangle represents a red–black subtree with a black height one less, i.e. its parent has black height zero in the second iteration. ; Remark : For simplicity, the sample code uses the
disjunction: :: U == NULL || U->color == BLACK
// considered black : and the
conjunction: :: U != NULL && U->color == RED
// not considered black : Thereby, it must be kept in mind that both statements are
not evaluated in total, if U == NULL. Then in both cases U->color is not touched (see
Short-circuit evaluation).(The comment considered black is in accordance with
requirement 2.) : The related if-statements have to occur far less frequently if the proposal) • Out of the body of the loop there are exiting branches to the cases
3,
6,
5,
4, and
1; section
"Delete case 3" of its own has three different exiting branches to the cases
6,
5 and
4. • Rotations occur in cases
6 and
5 + 6 and
3 + 5 + 6 – all outside the loop. Therefore, at most three rotations occur in total.
Delete case 1 The current node
N is the new root. One black node has been removed from every path, so the RB-properties are preserved. The black height of the tree decreases by 1.
Delete case 2 P,
S, and
S’s children are black. After painting
S red all paths passing through
S, which are precisely those paths
not passing through
N, have one less black node. Now all paths in the subtree rooted by
P have the same number of black nodes, but one fewer than the paths that do not pass through
P, so
requirement 4 may still be violated. After relabeling
P to
N the
loop invariant is fulfilled so that the rebalancing can be iterated on one black level (= 1 tree level) higher.
Delete case 3 The sibling
S is red, so
P and the nephews
C and
D have to be black. A at
P turns
S into
N’s grandparent. Then after reversing the colors of
P and
S, the path through
N is still short one black node. But
N now has a red parent
P and after the reassignment a black sibling
S, so the transformations in cases 4, 5, or 6 are able to restore the RB-shape.
Delete case 4 The sibling
S and
S’s children are black, but
P is red. Exchanging the colors of
S and
P does not affect the number of black nodes on paths going through
S, but it does add one to the number of black nodes on paths going through
N, making up for the deleted black node on those paths.
Delete case 5 The sibling
S is black,
S’s close child
C is red, and
S’s distant child
D is black. After a at
S the nephew
C becomes
S’s parent and
N’s new sibling. The colors of
S and
C are exchanged. All paths still have the same number of black nodes, but now
N has a black sibling whose distant child is red, so the constellation is fit for case D6. Neither
N nor its parent
P are affected by this transformation, and
P may be red or black ( in the diagram).
Delete case 6 The sibling
S is black,
S’s distant child
D is red. After a at
P the sibling
S becomes the parent of
P and
S’s distant child
D. The colors of
P and
S are exchanged, and
D is made black. The whole subtree still has the same color at its root
S, namely either red or black ( in the diagram), which refers to the same color both before and after the transformation. This way
requirement 3 is preserved. The paths in the subtree not passing through
N (i.o.w. passing through
D and node
3 in the diagram) pass through the same number of black nodes as before, but
N now has one additional black ancestor: either
P has become black, or it was black and
S was added as a black grandparent. Thus, the paths passing through
N pass through one additional black node, so that
requirement 4 is restored and the total tree is in RB-shape. Because the algorithm transforms the input without using an auxiliary data structure and using only a small amount of extra storage space for auxiliary variables it is
in-place. == Proof of bounds ==