《算法导论》笔记 第13章 13.3 插入
【笔记】
void rbInsert(NODE *z) { NODE *y = nil; NODE *x = root; while (x != nil) { y = x; if (z->key < x->key) { x = x->l; } else { x = x->r; } } z->p = y; if (y == nil) { root = z; } else { if (z->key < y->key) { y->l = z; } else { y->r = z; } } z->l = nil; z->r = nil; z->c = RED; rbInsertFixup(z); } void rbInsertFixup(NODE *z) { NODE *y; while (z->p->c == RED) { if (z->p == z->p->p->l) {// z 的父亲是爷爷的左儿子 y = z->p->p->r;// z 的叔叔 y if (y->c == RED) {// case 1:叔叔是红的 z->p->c = BLACK;// 将 z 的父亲与叔叔置为黑 y->c = BLACK; z->p->p->c = RED;// 将 z 的爷爷置为红 z = z->p->p;// 问题上移两层 } else { if (z == z->p->r) {// case 2:z 是右儿子 z = z->p; leftRotate(z);// 左旋,转为 case 3 } z->p->c = BLACK;// case 3:z 是左儿子,对z的爷爷做一次右旋即可完成维护 z->p->p->c = RED; rightRotate(z->p->p); } } else if (z->p == z->p->p->r) {// z 的父亲是爷爷的右儿子 y = z->p->p->l;// z 的叔叔 y if (y->c == RED) {// case 1:叔叔是红的 z->p->c = BLACK;// 将 z 的父亲与叔叔置为黑 y->c = BLACK; z->p->p->c = RED;// 将 z 的爷爷置为红 z = z->p->p;// 问题上移两层 } else { if (z == z->p->l) {// case 2:z 是左儿子 z = z->p; rightRotate(z);// 右旋,转为 case 3 } z->p->c = BLACK; z->p->p->c = RED; leftRotate(z->p->p); } } } root->c = BLACK; }
【练习】
13.3-1 RB-INSERT中假设新插入的节点是红的。注意如果将z着为黑色,则红黑树的性质4)就不会被破坏。那么我们为什么没有选择将z着为黑色呢?
性质5)被破坏。
13.3-2 在将关键字41,38,31,12,19,8插入一棵初始为空的红黑树中之后结果树是什么样子?
13.3-3 假设3种情景中子树αβγδε的黑高度都是k。标上各个结点的黑高度,以验证图中所示的各种转换能保证性质5)。
case 1:皆为k
case 2:皆为k
case 3:皆为k
13.3-4 证明RB-INSERT-FIXUP永远不会将nil的COLOR设置为RED。
case 1:将z的爷爷置为红,考虑z的爷爷为nil的情况,则z为root的儿子,而在该情况下,root不是nil的儿子,因此不会进入任何case中。
case 2、3:对z的爷爷做一次右旋并染为红,若z的爷爷为nil,与case 1同样的原因,不会出现这种情况。
综上,nil永远不会被设置为RED。
13.3-5 考虑用RB-INSERT插入n个结点而成的一棵红黑树。证明:如果n>1,则该树至少有一个红结点。
当n==2时,不进行维护,该树有一个红叶子结点。
假设n==k-1时,至少有一个红结点。
当n==k时,case 1中,一黑三红变为两黑两红,至少有两个红结点;case 2与case 3中,两红一黑结点数量不变。若有红的根结点被染为黑,仍然剩下至少一个红结点。
因此n>1时该树至少一个红结点。
13.3-6 说明如果红黑树的表示中不提供父指针的话,应当如何有效的实现RB-INSERT。