Algorithm Search⌘K

Proofs: Red-black tree deletion

These are the human proofs of Red-black tree deletion, at full length.

Deletion keeps the left-leaning red-black rules full

This proof shows: correctness.

The rules are (L1) search order, (L2) no red right child, (L3) no red node with a red left child, (L4) the same number of black nodes on every path from the root to nil, and (L5) a black root. For a node hh, write bh(h)bh(h) for the number of black nodes on a path from hh down to nil, counting hh itself, with bh(nil)=0bh(\text{nil}) = 0; it is well defined when (L4) holds in the subtree of hh. Call a subtree valid when (L1) to (L4) hold in it; its root may be red. In a valid subtree, a red node has two black children: the left one by (L3), the right one by (L2).

Lemma A (the steps). A rotation of a red link, where the child moves up, takes the color of the old top, and the old top becomes red, keeps (L1), keeps (L4) in the subtree, and keeps bhbh of the top. A color flip at a node whose two children both have the color opposite to its own keeps (L1), (L4) and bhbh of the top.

Proof. A rotation keeps the in-order sequence of the keys. For ROTATE-LEFT(h)(h) with x=h.rightx = h.right red, let cc be the color of hh and α\alpha, β\beta, γ\gamma the subtrees h.lefth.left, x.leftx.left, x.rightx.right. Before, a path from the top to α\alpha, β\beta or γ\gamma meets the node hh of color cc and, for β\beta and γ\gamma, the red xx. After, it meets the node xx of color cc and, for α\alpha and β\beta, the red hh. Red nodes add nothing, so each path has the same count. ROTATE-RIGHT is the mirror image. A flip at a black node with two red children makes the node red and the children black: a path from the top meets one black node before (the top) and one after (a child). The other flip is the reverse. Neither step changes keys. □\square

A call REMOVE(h,k)(h, k) has the precondition that k∈K(h)k \in K(h), that (L1), (L3), (L4) hold in the subtree of hh and (L2) holds at every node except possibly at hh, and that one of these holds:

  1. (P1) hh is red, with two black children;
  2. (P2) hh is black, h.lefth.left is red and h.righth.right is black;
  3. (P3) hh is black, h.lefth.left is black, h.righth.right is red, and k≥h.keyk \ge h.key.

In the 2-3 view, (P1) and (P2) say that hh is not a 2-node, so a key can leave it. The postcondition is that the result xx is valid, with keys K(h)∖{k}K(h) \setminus \{k\} and bh(x)=bh(h)bh(x) = bh(h), and that xx is black if hh was black when the call began. DELETE-MIN(h)(h) has the same precondition with (P1) or (P2), with kk the least key, and the same postcondition.

Lemma 2 (FIX-UP in deletion). If both children of hh are valid with the same bhbh, and if hh is red only when both children are black, then FIX-UP(h)(h) returns a valid subtree with the same keys and bhbh. If hh is black and h.righth.right is black, the result is hh itself, black.

Proof. If hh is red, its children are black and no test is true. If hh is black: with two black children nothing changes; with a red left child and a black right child, line L23 does not apply, since the left child is valid and red, so its left child is black; with a black left child and a red right child, line L22 rotates left and gives a black top with a red left child hh whose two children are black, as in Lemma 1; with two red children, line L24 flips and gives a red top with two black children. □\square

Lemma 3 (MOVE-RED-LEFT). Let hh be red with valid black children ll and rr, and let l.leftl.left be black. After MOVE-RED-LEFT(h)(h), the subtree has the same keys and bhbh, (L1) and (L4) hold, and either (a) the top is hh, black, with two red children, each with two black children, or (b) the top is red, its right child is black and valid, and its left child is the old hh, black, with the red left child ll (whose children are black) and a black right child.

Proof. Line L5 flips at hh, a red node with two black children: hh is black, and ll and rr are red. The children of ll are black (l.leftl.left by assumption, l.rightl.right by (L2)), and r.rightr.right is black by (L2). If r.leftr.left is black, the result is (a). Else let s=r.lefts = r.left, red, with two black children. Line L6 rotates right at rr: ss takes the red color of rr and rr becomes its red right child, whose left child is the old s.rights.right, black. Then it rotates left at hh: ss moves up with the black color of hh, hh becomes its red left child, and the right child of hh is the old s.lefts.left, black. Then it flips at ss, a black node with two red children: ss is red, and hh and rr are black. Now hh has the red left child ll and a black right child, and rr has two black children. Every step is one of Lemma A. □\square

Lemma 4 (MOVE-RED-RIGHT). Let hh be red with valid black children ll and rr, and let r.leftr.left be black. After MOVE-RED-RIGHT(h)(h), the subtree has the same keys and bhbh, (L1) and (L4) hold, and either (a) the top is hh, black, with two red children, each with two black children, or (b) the top tt is red with two black children; t.leftt.left is valid, and t.rightt.right is the old hh, black, with a black left child and the red right child rr, whose children are black; and t.key<h.keyt.key < h.key.

Proof. Line L7 flips at hh: hh is black, and ll and rr are red. The children of rr are black (r.leftr.left by assumption, r.rightr.right by (L2)), and l.rightl.right is black by (L2). If l.leftl.left is black, the result is (a). Else l.leftl.left is red, with black children. Line L8 rotates right at hh: ll moves up with the black color of hh, hh becomes its red right child, and the left child of hh is the old l.rightl.right, black. Then it flips at ll, a black node with two red children: ll is red, l.leftl.left is black, and hh is black. The node hh keeps the red right child rr. Since ll was the left child of hh, l.key<h.keyl.key < h.key. □\square

Lemma 5 (REMOVE and DELETE-MIN). Under the precondition, REMOVE(h,k)(h, k) and DELETE-MIN(h)(h) meet the postcondition.

Proof. By induction on the size. In every case below, the recursive call meets the precondition, so by induction it returns a valid subtree with the same bhbh as the child it replaces; then Lemma 2 applies to the last line, and we check its two conditions and the color of the result.

Case k<h.keyk < h.key (lines L9 to L11). Since (P3) needs k≥h.keyk \ge h.key, this case has (P1) or (P2). The key is in h.lefth.left, which is not nil.

  • (P2): h.lefth.left is red with black children, so line L10 does nothing and the call on h.lefth.left has (P1). Line L11 replaces h.lefth.left; the right child of hh is black and unchanged. By Lemma 2, the result is hh, black.
  • (P1) and h.left.lefth.left.left red: line L10 does nothing. The call on the black h.lefth.left has (P2) and returns a black node. At FIX-UP, hh is red with two black children, so Lemma 2 applies.
  • (P1) and h.left.lefth.left.left black: h.righth.right is not nil, since bh(h.right)=bh(h.left)≥1bh(h.right) = bh(h.left) \ge 1. Line L10 calls MOVE-RED-LEFT. In Lemma 3 (a), the call on the red left child has (P1), and at FIX-UP the top is black. In Lemma 3 (b), kk is less than the key of the old hh, which is the left child of the new top, so the recursion goes there, with (P2), and returns a black node; at FIX-UP the top is red with two black children.

Case k≥h.keyk \ge h.key (lines L12 to L16).

  • (P2): line L12 rotates right at hh. The new top tt is the old h.lefth.left, black, with the black left child h.left.lefth.left.left (by (L3)) and the red right child hh, whose children are black. Now k>t.keyk > t.key, line L13 does not apply (t.right≠t.right \ne nil), line L14 does nothing (t.rightt.right is red), and line L16 calls REMOVE on the red hh, which has (P1). At FIX-UP, tt is black with a black left child, so Lemma 2 gives a black result.
  • (P3): line L12 does nothing, line L13 does not apply (h.right≠h.right \ne nil), and line L14 does nothing (h.righth.right is red). The red right child has two black children, by (L3) and (L2) below hh. If k=h.keyk = h.key, line L15 calls DELETE-MIN on it, and else line L16 calls REMOVE on it; both calls have (P1). At FIX-UP, hh is black with a black left child, and the result is black.
  • (P1): line L12 does nothing. If k=h.keyk = h.key and h.righth.right is nil, then bh(h.left)=0bh(h.left) = 0 and h.lefth.left is black, so h.lefth.left is nil: hh is a red leaf, and line L13 returns nil, with bh=0=bh(h)bh = 0 = bh(h). Else h.righth.right is not nil, and neither is h.lefth.left, by (L4). If h.right.lefth.right.left is red, line L14 does nothing, and the call at line L15 or L16 on the black h.righth.right has (P2) and returns a black node; at FIX-UP, hh is red with two black children. If h.right.lefth.right.left is black, line L14 calls MOVE-RED-RIGHT. In Lemma 4 (a), the call on the red right child has (P1), and the top is black at FIX-UP. In Lemma 4 (b), the new top tt has t.key<h.key≤kt.key < h.key \le k, so line L15 does not apply, and line L16 calls REMOVE on the old hh, which is black, with a black left child and a red right child, and k≥h.keyk \ge h.key: (P3). It returns a black node, so at the FIX-UP of tt, tt is red with two black children.

When line L15 runs, h.keyh.key becomes the least key mm of h.righth.right. Every key of h.lefth.left is less than k<mk < m, and every other key of h.righth.right is greater than mm, so after DELETE-MIN removes mm from h.righth.right, (L1) holds and the key kk is gone.

DELETE-MIN. If h.lefth.left is nil (line L18), then (P2) is impossible, so hh is red, and as above hh is a red leaf and the result is nil. Else lines L19 to L21 run the case k<h.keyk < h.key above, with DELETE-MIN in place of REMOVE.

In every case the keys are K(h)∖{k}K(h) \setminus \{k\}, and bhbh is kept, by Lemma A, by induction and by Lemma 2. A result that comes from a call with hh black is black, as shown in each case. □\square

DELETE. Line L1 makes sure that kk is in the tree. Before line L2 the tree is valid with a black root. If both children of the root are black, line L2 paints the root red, which subtracts one from every path and so keeps (L4); now (P1) holds. Else the root has a red child, which is the left one by (L2), and (P2) holds. By Lemma 5, REMOVE returns a valid tree without kk. Line L4 paints the root black, which keeps (L4) and gives (L5).

Conclusion

Theorem. If TT is a left-leaning red-black tree, then after DELETE(T,k)(T, k) it is a left-leaning red-black tree whose keys are the old keys without kk.

Proof. If kk is not in TT, line L1 returns with no change. Else this is the paragraph on DELETE above, with Lemma 5. Each call of REMOVE or DELETE-MIN moves one level down, so the procedure stops after at most h+1h + 1 calls, where hh is the height. ■\blacksquare

Back to Red-black tree deletion