Red-Black Trees: Deletion

by math_explorer, Oct 26, 2010, 10:51 AM

Before we talk about that deletion procedure, we need to figure out how to delete a node in the general case.

[asy]unitsize(.4cm);

pair pa=(0,0);
pair pb=(-3, -2);
pair pc=(-5, -4);
pair pd=(-1, -4);
pair pe=(3, -2);
pair pf=(-2, -6);

draw(pa--pb);
draw(pb--pc);
draw(pb--pd);
draw(pa--pe);
draw(pd--pf);

transform t = shift(pa);
fill(t*unitcircle, red+gray(.5));
label("$5$", t*(0, 0.6), S);

t = shift(pb);
fill(t*unitcircle, gray(.5));
label("$e$", t*(0, 0.6), S);

t = shift(pc);
fill(t*unitcircle, gray(.5));
label("$\varphi$", t*(0, 0.6), S);

t = shift(pd);
fill(t*unitcircle, blue+gray(.5));
label("$\pi$", t*(0, 0.6), S);

t = shift(pe);
fill(t*unitcircle, gray(.5));
label("$4!$", t*(0, 0.6), S);

t = shift(pf);
fill(t*unitcircle, green+gray(.5));
label("$2.9$", t*(0, 0.6), S);
[/asy]
So anyway, suppose we have this awkward binary search tree which probably can't be exactly expressed on a computer unless you've got symbolic manipulation and very intelligent comparison features. There are essentially three cases.

1. Delete the green node, $2.9$, with 0 children. Since it's a leaf node, no problem. Just remove it, and replace with nil if necessary.
2. Delete the blue node, $\pi$, with 1 child. This is pretty easy, too: just take it out and reconnect its child with its parent, in this case, $2.9$ and $e$.
3. Delete the red node, $5$, with 2 children. (It also happens to be the root, but that's not important.) We instead overwrite it with its predecessor, $\pi$, and delete the old $\pi$ node. This reduces to case 2 or 1, since the predecessor can't have a right child. Yay.

Yep, so that's how you delete.

Righty then, on to the red-black deletion procedure. So first we do what we outlined above, of course, and figure out how badly we messed up the Red-Black Rules, and try to fix it.

Okay. Case 1 is actually a special case of Case 2, when the part below the deleted node consists of nothing. Case 3 also ends up in Case 2, given that the overwrite keeps the host's original color, so the color configuration there don't change. So we just have to deal with a spliced-out node, maybe $\pi$ in this instance.

Suppose $\pi$ was red. Then both parts that were originally had to be connected to $\pi$ were black, so splicing them together won't break the no-reds-together rule. Also, the equal-black-paths aren't broken either (annoying meticulous two-column casework left to the reader). It works, just that way.

Suppose $\pi$ was black. We've now gotten rid of a black node in one of those paths, and possibly made two reds touch as well. Ouch.

Let's see what we can do to fix this. We know that whatever node we spliced out, $\pi$, only had one child (or none). Here that would be $2.9$. Well, every path that went through $\pi$ and still exists now must go through $2.9$, and we need to readd a black node to each of those paths. Let's make $2.9$ black! We're done!

Dammit. $2.9$ might have already been black. If it's red, we're done, so let's see what happens if $2.9$ was black. Let's pretend we can make $2.9$ DOUBLE-BLACK. That works, but we don't allow that kind of color, so we'll have to figure out how to fix it. Hmm...

(Also, to prevent us somehow using $2.9$ as a variable later, we'll just call the DOUBLY-BLACK node $x$. And we'll color it a bright magenta, which is what DOUBLY-BLACK looks like in cartoons. Or maybe, I don't know.)

Okay, let's look at $x$'s sibling.
[asy]
unitsize(.4cm);

pair pa=(0,0);
pair pb=(-3, -2);
pair pc=(3, -2);
pair pd=(1, -4);
pair pe=(5, -4);

draw(pa--pb);
draw(pa--pc);
draw(pc--pd);
draw(pc--pe);

transform t = shift(pa);
fill(t*unitcircle, black);
label("$A$", t*(0, 0.6), S, white);

t = shift(pb);
fill(t*unitcircle, red+blue);
label("$B$", t*(0, 0.6), S);

t = shift(pc);
fill(t*unitcircle, red+gray(.5));
label("$C$", t*(0, 0.6), S);

t = shift(pd);
fill(t*unitcircle, black);
label("$D$", t*(0, 0.6), S, white);

t = shift(pe);
fill(t*unitcircle, black);
label("$E$", t*(0, 0.6), S, white);
[/asy]
Suppose it's red. We don't want that, because they're siblings, and they're so far (read (no pun intended (depending on whether you read "read" in such a situation as "red" or as "reed" (read: whatever ( :lol: (invalid reference to xkcd 541 (which I saw used in the Python documentation SOMEWHERE (don't overuse caps, guys (Python rocks)))))))): two black-levels) apart! Let's fix it for them, by left-rotating $A$ and $C$, so that $D$ becomes $x$'s brother. Crunch. (Picture left to the reader as an exercise.)

[asy]
unitsize(.4cm);

pair pa=(0,0);
pair pb=(-3, -2);
pair pc=(3, -2);
pair pd=(1, -4);
pair pe=(5, -4);

draw(pa--pb);
draw(pa--pc);
draw(pc--pd);
draw(pc--pe);

transform t = shift(pa);
fill(t*unitcircle, gray);
label("$A$", t*(0, 0.6), S);

t = shift(pb);
fill(t*unitcircle, red+blue);
label("$B$", t*(0, 0.6), S);

t = shift(pc);
fill(t*unitcircle, black);
label("$C$", t*(0, 0.6), S, white);

t = shift(pd);
fill(t*unitcircle, gray);
label("$D$", t*(0, 0.6), S, black);

t = shift(pe);
fill(t*unitcircle, gray);
label("$E$", t*(0, 0.6), S, black);
[/asy]
Otherwise, $x$'s sibling is black. You'll notice the other nodes are gray, which isn't a color, but I don't like using other people's storage for these images even though certain other people *cough* really like it, so I'm going to smoosh all these other cases into one.

Suppose $D$ and $E$ are both black. Then we can take away one black-level from $B$ and $C$ and give it to $A$. If $A$ is now DOUBLY-BLACK, we can use RECURSION. Whee.

Suppose $D$ is red, $E$ is black. Then we can right-rotate $C$ and $D$, swap their colors, and reduce to the next case.

Suppose $E$ is red. Then we can left-rotate $A$ and $C$, take away the extra blackness from $A$, and give it to $E$. No recursion necessary!

Yay, we're done!
This post has been edited 1 time. Last edited by math_explorer, Aug 19, 2011, 9:40 AM

Comment

0 Comments

♪ i just hope you understand / sometimes the clothes do not make the man ♫ // https://beta.vero.site/

avatar

math_explorer
Archives
+ September 2019
+ February 2018
+ December 2017
+ September 2017
+ July 2017
+ March 2017
+ January 2017
+ November 2016
+ October 2016
+ August 2016
+ February 2016
+ January 2016
+ September 2015
+ July 2015
+ June 2015
+ January 2015
+ July 2014
+ June 2014
inv
+ April 2014
+ December 2013
+ November 2013
+ September 2013
+ February 2013
+ April 2012
Shouts
Submit
  • how do you have so many posts

    by krithikrokcs, Jul 14, 2023, 6:20 PM

  • lol⠀⠀⠀⠀⠀

    by math_explorer, Jan 20, 2021, 8:43 AM

  • woah ancient blog

    by suvamkonar, Jan 20, 2021, 4:14 AM

  • https://artofproblemsolving.com/community/c47h361466

    by math_explorer, Jun 10, 2020, 1:20 AM

  • when did the first greed control game start?

    by piphi, May 30, 2020, 1:08 AM

  • ok..........

    by asdf334, Sep 10, 2019, 3:48 PM

  • There is one existing way to obtain contributorship documented on this blog. See if you can find it.

    by math_explorer, Sep 10, 2019, 2:03 PM

  • SO MANY VIEWS!!!
    PLEASE CONTRIB
    :)

    by asdf334, Sep 10, 2019, 1:58 PM

  • Hullo bye

    by AnArtist, Jan 15, 2019, 8:59 AM

  • Hullo bye

    by tastymath75025, Nov 22, 2018, 9:08 PM

  • Hullo bye

    by Kayak, Jul 22, 2018, 1:29 PM

  • It's sad; the blog is still active but not really ;-;

    by GeneralCobra19, Sep 21, 2017, 1:09 AM

  • dope css

    by zxcv1337, Mar 27, 2017, 4:44 AM

  • nice blog ^_^

    by chezbgone, Mar 28, 2016, 5:18 AM

  • shouts make blogs happier

    by briantix, Mar 18, 2016, 9:58 PM

91 shouts
Contributors
Tags
About Owner
  • Posts: 583
  • Joined: Dec 16, 2006
Blog Stats
  • Blog created: May 17, 2010
  • Total entries: 327
  • Total visits: 356965
  • Total comments: 368
Search Blog
a