From: Doug Dunham Subject: RB-tree example To: cs4521-1-s2002@d.umn.edu (CS 4521) Date: Thu, 7 Mar 2002 16:44:22 -0600 (CST) I have attached below the example that I tried to work out in the lab session yesterday. I think it is now correct, but please look it over and tell me if I have made a mistake. Also, one of the students has found an interactive Java program that illustrates red-black tree operations. It is at: http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html I have put up a link to it on the "Lab and Homework Assignments" page of the class web site. Note that it seems to do things differently than our book, doing rotations before colorings, for example. It produced the same trees as in the example below during insertion, but the deletion of node (5) produced a different result than below, though both are correct red-black trees. There are different algorithms for red-black tree insertion and deletion than are presented in our text. Here is the example of red-black tree insertions and deletions: Problem 1: insert 9 8 7 3 5 2 into a red-black tree in that order. Insert 9: z (9) R and is the root going into RB-INSERT-FIXUP Since p[z] is nil and B, we skip the loop and do line 16, making root B Insert 8: (9) B / z (8) R Since p[z] is B, we skip the loop (and do line 16, which has no effect). Insert 7: (9) B This is Case 3, so we change the colors of p[z] and / \ p[p[z]], and right-rotate: (8) B (8) R nil B / \ / y (7) R (9) R z (7) R Insert 3: (8) B This is Case 1, so we change the colors of p[z], y, / \ and p[p[z]], and move z up z' (8) R (7) R (9) R the tree to its grandparent / \ / y (7) B (9) B z (3) R / (3) R Since p[z'] is B, the loop ends and we color the root B (not shown above). Insert 5: (8) B This is Case 2, so we move z up to its parent (3) / \ and left rotate: (8) B (7) B (9) B / \ / \ (7) B (9) B (3) R nil y / \ \ (5) R nil y z (5) R / z (3) R This falls through to Case 3, which recolors p[z] and p[p[z]], (8) B and right-rotates: / \ (5) B (9) B / \ z (3) R (7) R Insert 2: (8) B This is Case 1 again, so we change (8) B / \ colors of p[z], y, and p[p[z]], and / \ (5) B (9) B move z up the tree to its grandparent z' (5) R (9) B / \ / \ (3) R (7) R (3) B (7) B / y / z (2) R (2) R Since p[z'] is B, the loop ends (and root is colored B -- no effect). Problem 2: delete 2 5 3 7 8 9 in that order from the tree above. This is not really a good example, since it doesn't show many cases. However, it does show that delete doesn't exactly undo what insert does (as we might suspect, since insertion is always at a leaf, but we may delete an interior node). Delete 2 (R): (8) B No fixup is done, since y = (2) was R / \ (5) R (9) B / \ (3) B (7) B Delete 5 (R): (8) B First, the key 5 is replaced by its successor, 7, / \ then y = the old node (7), which is B, is deleted, (7) R (9) B so fixup must be done. This is Case 2' in the / \ missing "else" clause -- x's sibling, w, and (3) B nil B both its children (nils) are B, so we color w red w x and move x up to its parent: (8) B / \ Then, since x' is R, we leave the loop and x' (7) R (9) B color x' B at line 23 (not shown). / (3) R Delete 3 (R): (8) B No fixup is done, since y = (3) was R. / \ (7) B (9) B Delete 7 (B): (8) B This is Case 2 (x's sibling, w, and x' (8) B / \ both its children (nils) are B), so \ nil B (9) B so we color w red and move x up to (9) R x w its parent: Since x' is the root, the loop ends (and x' is colored B -- no effect). Delete 8 (B): (9) B Key 8 is replaced by its successor, 9, and y = the old node (9) is deleted and no fixup is done, since y was R. Delete 9 (B): root becomes nil. In RB-DELETE, x becomes the right child of the old node (9), which is nil, and the root becomes x in line 9. So the loop is not entered in RB-DELETE-FIXUP and we are done.