/*---------------------------------------*\ | p p | | / \ / \ | | x d rotate left y d | | / \ ===========> / \ | | a y x c | | / \ / \ | | b c a b | \*---------------------------------------*/ // 左旋,参数一为左旋点,参数二为根节点 template <classNodePtr> voidrb_tree_rotate_left(NodePtr x, NodePtr& root)noexcept{ auto y = x->right; x->right = y->left; if (y->left != nullptr) y->left->parent = x; y->parent = x->parent;
// 如果 x 为根节点,让 y 顶替 x 成为根节点 if (x == root) root = y; elseif (rb_tree_is_lchild(x)) x->parent->left = y; else x->parent->right = y;
// 调整 x 与 y 的关系 y->left = x; x->parent = y; }
/*----------------------------------------*\ | p p | | / \ / \ | | d x rotate right d y | | / \ ===========> / \ | | y a b x | | / \ / \ | | b c c a | \*----------------------------------------*/ // 右旋,参数一为右旋点,参数二为根节点 template <classNodePtr> voidrb_tree_rotate_right(NodePtr x, NodePtr& root)noexcept{ auto y = x->left; x->left = y->right; if (y->right != nullptr) y->right->parent = x; y->parent = x->parent;
// 如果 x 为根节点,让 y 顶替 x 成为根节点 if (x == root) root = y; elseif (rb_tree_is_lchild(x)) x->parent->left = y; else x->parent->right = y;
// y 是可能的替换节点,指向最终要删除的节点 auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z); // x 是 y 的一个独子节点或 NIL 节点 auto x = y->left != nullptr ? y->left : y->right; // xp 是 x 的父节点 NodePtr xp = nullptr;
// case3 // y != z 说明 z 有两个非空子节点,此时 y 是 z 的后继节点,x 指向 y 的非空子节点。 // 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y 指向 z if (y != z) { z->left->parent = y; y->left = z->left;
// 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子 // x 替换 y 的位置 if (y != z->right) { xp = y->parent; if (x != nullptr) x->parent = y->parent; y->parent->left = x; y->right = z->right; z->right->parent = y; } else xp = y;
// 连接 y 与 z 的父节点 if (root == z) root = y; elseif (z->parent->left == z) z->parent->left = y; else z->parent->right = y;
y->parent = z->parent; tinystl::swap(y->color, z->color); y = z; }
// case1、case2 // y == z 说明 z 至多只有一个孩子 else { xp = y->parent; if (x) x->parent = y->parent;
// 连接 x 与 z 的父节点 if (root == z) root = x; elseif (z->parent->left == z) z->parent->left = x; else z->parent->right = x;
// 此时 z 有可能是最左节点或最右节点,更新数据 if (leftmost == z) leftmost = x == nullptr ? xp : rb_tree_min(x); if (rightmost == z) rightmost = x == nullptr ? xp : rb_tree_max(x); }
// 仅在删除黑色节点时需要调整 if (!rb_tree_is_red(y)) { // 注意这里的循环条件: !rb_tree_is_red(x),当遇到 case3 的情况时会转而处理 P 节点 // 此时 p == x,会再进行一次条件判断,当 p 为红色时,便为 case4 的情况 // 直接跳出循环,最后将 x 设为黑色,结束调整。 while (x != root && (x == nullptr || !rb_tree_is_red(x))) { if (x == xp->left) { auto brother = xp->right; // case2:兄弟节点为红色节点,旋转父节点 if (rb_tree_is_red(brother)) { rb_tree_set_red(xp); // 父节点变为红色 rb_tree_set_black(brother); // 兄弟节点变为黑色 rb_tree_rotate_left(xp, root); // 左旋 brother = xp->right; // 更新兄弟节点 } // case3: 兄弟节点及两个子节点均为黑色 if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) && (brother->right == nullptr || !rb_tree_is_red(brother->right))) { rb_tree_set_red(brother); // 兄弟节点变为红色 x = xp; // 父节点成为当前节点 xp = xp->parent; // 父节点的父节点成为父节点 // 此时如果 p 为红色会直接跳出循环 } else { // case5: 兄弟节点同侧的节点为黑色 if (brother->right == nullptr || !rb_tree_is_red(brother->right)) { if (brother->left != nullptr) rb_tree_set_black(brother->left); // 兄弟节点的左子节点变为黑色 rb_tree_set_red(brother); // 兄弟节点变为红色 rb_tree_rotate_right(brother, root); // 右旋 brother = xp->right; // 更新兄弟节点 } // 处理之后变为 case6 // case6: 兄弟节点的同侧节点为红色 brother->color = xp->color; // 兄弟节点变为父节点的颜色 rb_tree_set_black(xp); // 父节点变为黑色 if (brother->right != nullptr) rb_tree_set_black(brother->right); // 兄弟节点的右子节点变为黑色 rb_tree_rotate_left(xp, root); // 左旋 break; } } // x 为右子节点,对称处理 else { auto brother = xp->left; // case 1 if (rb_tree_is_red(brother)) { rb_tree_set_black(brother); rb_tree_set_red(xp); rb_tree_rotate_right(xp, root); brother = xp->left; } // case 2 if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) && (brother->right == nullptr || !rb_tree_is_red(brother->right))) { rb_tree_set_red(brother); x = xp; xp = xp->parent; } else { // case 3 if (brother->left == nullptr || !rb_tree_is_red(brother->left)) { if (brother->right != nullptr) rb_tree_set_black(brother->right); rb_tree_set_red(brother); rb_tree_rotate_left(brother, root); brother = xp->left; } // 转为 case 4 brother->color = xp->color; rb_tree_set_black(xp); if (brother->left != nullptr) rb_tree_set_black(brother->left); rb_tree_rotate_right(xp, root); break; } } } // 将 x 的颜色改为黑色,有可能是 root 节点也有可能是 case4 跳出了循环 if (x != nullptr) rb_tree_set_black(x); } return y; // 这里返回的值实际上没有用到 // 注意:执行完 rb_tree_erase_rebalance 保证了传入的 z,及要被删除的节点,此时一定不在树的结构中了 // 这意味着对其进行析构是安全的,不会破坏树的性质。 }
此外需要注意的是上一小节中提到的 stl_tree 中的注释:
1 2 3
// (2) when a node being deleted has two children its successor node // is relinked into its place, rather than copied, so that the only // iterators invalidated are those referring to the deleted node.