DSA DSA In Depth
0%
lesson red-black-treellrb2-3-trees

2-3-4 Trees, Red-Black Trees & Sedgewick's Left-Leaning Red-Black (LLRB) Isomorphism

7 min read Module 3.2: Self-Balancing, Augmented, Disk-Backed & Persistent Trees Updated Oct 23, 2026
📄 Cheat Sheet
Red-Black Trees in 4 Minutes — Color Invariants & Rebalancing
Michael Sambol Red-Black Trees in 4 Minutes — Color Invariants & Rebalancing Watch on YouTube ↗

Robert Sedgewick explains how Guibas & Sedgewick (1978) derived Red-Black Trees from 2-3-4 B-trees and how LLRB trees reduce implementation to 3 lines of rotation/flip code.

0:00 / --:--

The Four Classical Red-Black Invariants & The 2-3-4 B-Tree Bijection

In a standard Red-Black Tree (CLRS Chapter 13), every node (or incoming parent link) is colored either Red or Black subject to four invariants:

  1. Root Rule: The root is always Black.
  2. External Leaf Rule: Every null leaf sentinel is Black.
  3. Red Rule (No Red-Red Parent-Child): If a node is Red, both of its children are Black.
  4. Black-Height Rule (Perfect 2-3-4 Balance): Every simple path from any node $u$ down to any descendant null leaf contains the exact same number of Black nodes, denoted $\text{bh}(u)$ (the black-height).

Sedgewick's Left-Leaning (LLRB 2-3) Simplification: If we forbid 4-nodes from persisting at rest and force every 3-node's red glue edge to lean left, then right-leaning red links are illegal and two consecutive left-leaning red links represent a temporary 4-node awaiting a split (flipColors). Every LLRB insertion ascending the recursion stack runs the exact same 3 if-statements:

  1. if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h); — Lean a right-leaning 3-node to the left.
  2. if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); — Balance a skewed temporary 4-node so its two children are both red.
  3. if (isRed(h.left) && isRed(h.right)) flipColors(h); — Split the temporary 4-node into two 2-nodes and pass the middle key up to the parent as a red link!
Metric / Operation Red-Black Tree (Standard 2-3-4) LLRB Tree (2-3 Isomorphism) AVL Tree Comparison
Worst-Case Height $h(T)$ ≤ 2 log₂(N + 1) ≤ 2 log₂(N + 1) AVL is tighter: $\le 1.44 \log_2(N+2)$
insert(k) Rotations ≤ 2 Rotations Worst-Case O(log N) Worst / O(1) Avg AVL: $\le 2$ rotations worst-case
delete(k) Rotations ≤ 3 Rotations Worst-Case! O(log N) AVL: $O(\log N)$ rotations
Fixup Complexity (Amortized) O(1) Recolors + Rotations O(1) Amortized Splits Standard RB wins on write-heavy workloads

Lemma: Why a Red-Black Tree of $N$ Internal Nodes Has Height $h \le 2 \log_2(N + 1)$

Step 1 (Subtree Size Lower Bound via Black-Height): By induction on black-height $\text{bh}(x)$, the subtree rooted at any node $x$ contains at least $2^{\text{bh}(x)} - 1$ internal nodes. Base case: if $\text{bh}(x) = 0$, $x$ is a null leaf with $2^0 - 1 = 0$ internal nodes. Inductive step: for an internal node $x$, each child $c$ has black-height either $\text{bh}(x)$ (if $c$ is Red) or $\text{bh}(x) - 1$ (if $c$ is Black). By the Inductive Hypothesis, each child subtree has at least $2^{\text{bh}(x)-1} - 1$ nodes, so:

$$\text{size}(x) \ge 1 + 2\left(2^{\text{bh}(x)-1} - 1\right) = 2^{\text{bh}(x)} - 1$$

Step 2 (Relating $h$ to $\text{bh}(\text{root})$): By the Red Rule (no two consecutive Red nodes on any path), at least half of the nodes along any root-to-leaf path of length $h$ must be Black: $\text{bh}(\text{root}) \ge h / 2$. Substituting into Step 1:

$$N \ge 2^{\text{bh}(\text{root})} - 1 \ge 2^{h/2} - 1 \implies 2^{h/2} \le N + 1 \implies h \le 2 \log_2(N + 1)$$

Self-Balancing BST: AVL Balance Factors & LLRB 2-3-4 Rotations
Height ≤ 1.44 log₂N (AVL) / 2 log₂N (RB)

Trace how AVL LL/LR/RR/RL rotations and Sedgewick Left-Leaning Red-Black (LLRB) local transformations (rotateLeft, rotateRight, flipColors) preserve in-order sequence and subtree sizes while bounding tree height.

Step 1 / 10
Custom Input:
Timeline

Invariant & State

Inserted 20: Red right-leaning link on 10 -> violates LLRB left-leaning invariant!
10(B) 20(R)
Operation
Insert 20 (Red)
Rebalance Action
Pending rotateLeft(10)
Black-Height (bh)
1
In-Order Keys
[10, 20, 30]
[Step 1] Inserted 20: Red right-leaning link on 10 -> violates LLRB left-leaning invariant!
1. 2-3 Tree 3-Node [E | M] ⟷ LLRB Left-Leaning Red Edge: E | M ⟷ M E 2. Temporary 4-Node [E | M | S] → flipColors(M): M E S → M E S LLRB 3-Step Bottom-Up Invariant Restoration: Step 1: if (red(h.R) && !red(h.L)) h = rotateLeft(h); // Fix right-leaning red Step 2: if (red(h.L) && red(h.L.L)) h = rotateRight(h); // Fix double-left red Step 3: if (red(h.L) && red(h.R)) flipColors(h);
flowchart LR Ins["Recursive insert into h.L or h.R"] --> S1{"isRed(h.R) AND !isRed(h.L) ?"} S1 -- "Yes" --> RL["h = rotateLeft(h)"] --> S2 S1 -- "No" --> S2{"isRed(h.L) AND isRed(h.L.L) ?"} S2 -- "Yes" --> RR["h = rotateRight(h)"] --> S3 S2 -- "No" --> S3{"isRed(h.L) AND isRed(h.R) ?"} S3 -- "Yes" --> Flip["flipColors(h) (Split 4-node)"] --> Ret["return h"] S3 -- "No" --> Ret

Hardware Reality: Why std::map, Java TreeMap, and Linux rbtree Choose Red-Black Over AVL

If AVL trees are shorter ($1.44 \log_2 N$ vs $2.00 \log_2 N$), why do C++ std::map, Java TreeMap, and the Linux kernel use standard Red-Black Trees instead? Because in a standard Red-Black Tree, insertion requires at most 2 rotations and deletion requires at most 3 rotations in the worst case (compared to $O(\log N)$ rotations for AVL deletion!). In concurrent or persistent environments where each rotation modifies cache lines or copies nodes along the spine, bounding structural pointer mutations to $O(1)$ worst-case rotations is decisive.

Implementation: Complete Sedgewick LLRB Insertion Engine

// C++20: Sedgewick Left-Leaning Red-Black (LLRB) Tree Insertion in 45 Lines
struct LLRBNode {
    int key;
    bool red = true; // New nodes are always inserted with a RED incoming link
    LLRBNode *left = nullptr, *right = nullptr;
    explicit LLRBNode(int k) : key(k) {}
};

inline bool isRed(const LLRBNode* x) noexcept { return x != nullptr && x->red; }

LLRBNode* rotateLeft(LLRBNode* h) noexcept {
    LLRBNode* x = h->right;
    h->right = x->left;
    x->left = h;
    x->red = h->red;
    h->red = true;
    return x;
}

LLRBNode* rotateRight(LLRBNode* h) noexcept {
    LLRBNode* x = h->left;
    h->left = x->right;
    x->right = h;
    x->red = h->red;
    h->red = true;
    return x;
}

void flipColors(LLRBNode* h) noexcept {
    h->red = !h->red;
    h->left->red = !h->left->red;
    h->right->red = !h->right->red;
}

LLRBNode* insertNode(LLRBNode* h, int key) {
    if (!h) return new LLRBNode(key);
    if (key < h->key)      h->left  = insertNode(h->left, key);
    else if (key > h->key) h->right = insertNode(h->right, key);

    // The 3-line LLRB invariant restoration pipeline:
    if (isRed(h->right) && !isRed(h->left))     h = rotateLeft(h);
    if (isRed(h->left)  && isRed(h->left->left)) h = rotateRight(h);
    if (isRed(h->left)  && isRed(h->right))      flipColors(h);
    return h;
}

Failure Modes & Adversarial Pitfalls

  • Forgetting to Force root->red = false After Insertion: When flipColors splits the root of the entire tree, root->red flips to true (which corresponds to growing the 2-3 tree upward by 1 black level). Always set root->red = false at the top-level insert(key) wrapper!
  • LLRB Deletion Asymmetry vs Standard RB Deletion: While LLRB insertion is 15 lines of code, LLRB deletion (moveRedLeft / moveRedRight) must push red links downward top-down to guarantee the target leaf is not a 2-node, performing $O(\log N)$ rotations on the way down and up, whereas classical CLRS Red-Black deletion performs at most 3 rotations.
Check yourself Question 1 of 4
Concept Check 2-3-4 Tree to Red-Black Tree Isomorphism recall

Under Guibas and Sedgewick's correspondence between 2-3-4 B-trees and standard Red-Black trees, how is a 4-node (containing 3 keys $a < b < c$ and 4 child links) represented?

⚡ Interactive Challenge · Staff Level

Algorithmic Design & Complexity Check

Analyze the invariant, asymptotic bound, and hardware behavior before selecting.

What invariant do `moveRedLeft` and `moveRedRight` maintain during the top-down descent of LLRB deletion, and what is the trade-off?

Key Takeaways

Red-Black Trees are an exact binary representation of 2-3-4 B-trees where Red edges glue keys horizontally inside a single 3-node or 4-node and Black edges represent vertical B-tree child links.
Every node x of black-height bh(x) roots a subtree of at least 2^bh(x) - 1 internal nodes; combined with bh(root) >= h/2, this proves height h <= 2 log₂(N + 1).
Classical Red-Black Trees require at most 2 rotations on insert and at most 3 rotations on delete in the worst case.
Sedgewick's Left-Leaning Red-Black (LLRB) Tree enforces a 1-to-1 bijection with 2-3 trees, reducing bottom-up rebalancing to rotateLeft, rotateRight, and flipColors.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue