Operations on Red-Black Trees




CS146

Chris Pollett

Apr 16, 2014

Outline

Introduction

Pseudo-code for Left-Rotate

Rotation operation

Insertion

RB-INSERT-FIXUP

Fix-up Remarks

Example of Tree Insert Failing Property 4

Fix-Up Loop Invariant

Proof of Loop Invariant

To show the loop invariance of the property of the last slide, we need to prove Initialization, Maintenance, and Termination conditions. We will prove these slightly out of order on the next few slides, starting below

Initialization: Prior to the first iteration of the loop, we started with a red-black tree with no violations and we added the red node `z`. We show each part of the invariant holds at the time RB-INSERT-FIXUP is called:

  1. When RB-INSERT-FIXUP is called, `z` is the red node that was added.
  2. If z.p is the root, then z.p started out black and did not change prior to the call of RB-INSERT-FIXUP.
  3. We have already seen that properties 1, 3, and 5 hold when RB-INSERT-FIXUP is called. If the tree violates property 2, then the red root must be the newly added node `z`, which is the only internal node in the tree. Because the parent and both children of `z` are the sentinel, which is black, the tree does not violate property 4. Thus, this violation of property 2 is the only violation of red-black properties in the entire tree. If the tree violates property 4, then, because the children of node `z` are black sentinels and the tree had no other violations prior to `z` being added, the violation must be because both `z` and `z.p` are red. Moreover, the tree violate no other red black properties.

Termination

When the loop terminates, it does so because `z.p` is black. (If `z` is the root, then `z.p` is the sentinel T.nil, which is black). Thus, the tree does not violate property `4` at loop termination. By the loop invariant, the only property that might fail to hold is property 2. Line 16 restores this property, too, so that when RB-INSERT-FIXUP terminates, all the red-black properties hold.

Maintenance

There are six cases in the while loop, but three are symmetric to the other three, depending on whether line 2 determines `z`'s parent `z.p` to be a left child or a right child of `z`'s grandparent `z.p.p`. We have given the code only for the situation in which `z.p` is a left child. We know `z.p.p` exists since by part (2) of the loop invariant, if `z.p` is the root, then `z.p` is black. Since we enter a loop iteration only if `z.p` is red, we know that z.p cannot be the root, so `z.p.p` exists.

We distinguish case 1 from cases 2 and 3 by the color of `z`'s parent's sibling or "uncle". Line 3 makes `y` point to `z`'s uncle `z.p.p`.right, and line 4 tests `y`'s color. If `y` is red, then we execute case 1. Otherwise, control passes to cases 2 and 3. In all three cases, `z`'s grandparent `z.p.p` is black, since its parent `z.p` is red, and property 4 is violated only between `z` and `z.p`.

More Maintenance -- Case 1 z's uncle y is red

Example of Case 1

The above picture illustrates this case. here both `z.p` and `y` are red. Because `z.p.p` is black, we can color both `z.p` and `y` black, thereby fixing the problem of `z` and `z.p` both being red, and we can color `z.p.p` red, thereby maintaining property 5. We then repeat the while loop with `z.p.p` as the new node `z`. Let's verify the loop invariant properties. Let `z' = z.p.p` denote the new `z`.

  1. Because this iteration colors `z.p.p` red, node `z'` is red at the start of the next iteration.
  2. The node `z'.p` is `z.p.p.p` in this iteration, and the color of this node does not change. If this node is the root, it was black prior to this iteration, and it remains black at the start of the next iteration.
  3. We have already argued that case 1 maintains property 5, and it does not introduce a violation of 1 and 3.
    If node `z'` is the root at the start of the next iteration, then case 1 corrected the lone violation of property 4. Since `z'` is red and it is the root, property 2 fails and it is only property violated, and this violation is due to `z'`.
    If node `z'` is not the root at the start of the next iteration, then case 1 has not created a violation of property 2. Case 1 corrected the lone violation of property 4 that existed at the start of this iteration. It then made `z'` red and left `z'.p` alone. If `z'.p` was black, there is no violation of property 4. If `z'.p` was red, coloring `z'` red created one violation of property 4 between `z'` and `z'.p`.

More Maintenance -- Case 2 and Case 3

Red black Trees Insert Case 2 and 3

Case 2 is when `z`'s uncle `y` is black and `z` is a right child. Case 3 is the same but `z` is a left child.

Case 2 and 3 are shown in the above figure.

Line 10-11 handle case 2. In case 2, node `z` is a right child of its parent. We use a left rotation to transform the situation into case 3, in which node `z` is a left child. Because `z` and `z.p` are red, the rotation affects neither the black height nor property 5. `z`'s uncle is now black as it would be in case 3.

To fix case 3, we do a right rotation as in the figure above and label the root black and C in the above red. Since `z`'s uncle was black and `z.p`'s right child was black. `C` will satisfy the red-black property. We have also fixed the only violation in the tree of property 4. Node B is now the root of the affected subtree and is black, so even if B were the root of the whole red-black tree, property two that the root is black will hold. Node `z` is still red above so (1) of our loop invariant holds, we have also just argued (2) and (3) hold. In fact, after this change the whole tree will be red back and the while loop will terminate.

Notice in total the fix code does at most 2 rotations. As is moves up the tree it will be `O(log n)`. So the whole procedure is `O(log n)`.