红黑树的bottomup-insert很容易实现, 而删除就不容易, 今天抄成功了Julienne Walker发在他网站上的算法, 为备忘, 总结一下。
首先, 删除red 节点, 不影响红黑树的有效性。利用这一点,我们寄希望于可以把其他情况都转化成删除红色节点。
其次, 跟在Binary search tree中一样, 删除一个节点K可以转化为
1,先找到这个节点的inorder predecessor(中序前一个) $K
2, 拷贝$K的内容到K,然后删除$K
Julienne Walker告诉我们,要转化成删除红色节点总是可以的。只要我们在向下搜索待删除key的时候,利用旋转,确保被删除的节点是红色, 并且不改变红黑树的性质(1,红色节点不能相连;2,每一个空节点到root的“black-height”都一样)
结合上面两点, 我们在搜索的过程中要把实际上“物理”删除的节点变成红色的, 具体变换如下:
假定刚刚比较过Q.data与data的大小, 知道该往Q的子节点T的方向继续搜索.(在找到Q.data == data后, 还继续搜索$Q,
为了让T的某个分支上满足设想, 即最后让$Q为红色, 我们希望将Q变成红色的, 如果它不是红的的话)
void RedBlackTree::remove(int data) { if (mRoot != NULL) { RBNode head = {0}; //great-parent, parent, iterator, ,founded node. RBNode *g, *p, *q, *t, *f = NULL; q = &head; g = p = NULL; q->r = mRoot; bool isRight = true; do { bool last = isRight; t = isRight ? q->r : q->l; g=p; p=q; q = t; isRight = q->data < data; t = isRight ? q->r : q->l; if (q->data==data) f=q; if (!is_red(q) && !is_red(t)) {//目标是使最后被删除的节点red, q或t是red都可以保证这一点 RBNode* othLink = isRight ? q->l : q->r; if (is_red(othLink)) { if (isRight) rotate_right(q); else rotate_left(q); if (last) p->l = q; else p->r = q; } else { RBNode* s = last ? p->l : p->r; if (s != NULL) { if (!is_red(s->l) && !is_red(s->r)) { p->red = 0; q->red = s->red = 1; } else { bool isPLeft = g->l == p; RBNode *&tmp = isPLeft ? g->l : g->r; RBNode *ss = last ? s->l : s->r; if (is_red(ss)) { if (last) rotate_right(tmp); else rotate_left(tmp); } else { if (last) rotate_left_right(tmp); else rotate_right_left(tmp); } tmp->red = q->red = 1; tmp->l->red = tmp->r->red=0; } } } } }while (t != NULL); if (f != NULL) { f->data = q->data; RBNode* &tmp = p->l==q ? p->l : p->r; tmp=q->l == NULL ? q->r : q->l; delete q; } if (mRoot != NULL) mRoot->red = 0; } }