插入節點主要分成三個步驟
map_node_t **pnode;
rb_link_node(node, parent, pnode);
rb_insert_color(node, &map->root);
內迴圈if/else邏輯是對稱,差別只在左右節點
情形一 叔叔節點是紅色
進行顏色對調並且往上再平衡
node = gparent
情形二 叔叔節點是黑色
2-1 : zig-zag情形
親代節點左旋轉
2-2 右旋轉祖父節點
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;
while ((parent = rb_parent(node)) && rb_is_red(parent)) {
gparent = rb_parent(parent);
if (parent == gparent->rb_left) {
{
struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle)) {
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_right == node) {
__rb_rotate_left(parent, root);
struct rb_node *tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(node);
__rb_rotate_right(gparent, root);
} else {
{
struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle)) {
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_left == node) {
__rb_rotate_right(parent, root);
struct rb_node *tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(node);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
這裡可以參考__rb_erase_augmented
的解說,對應到核心的程式碼
主要判斷條件
以此圖為例,假設刪除節點N
找到右子樹的最小節點t0取代N
如果t0有右子樹, 變成原本親代節點的左子樹
此圖為例,直接讓c1當節點P的右子節點
如果節點node是黑色節點
需要進行樹的再平衡
void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color;
if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
// has 2 children
else {
struct rb_node *old = node, *left;
node = node->rb_right;
// node becomes smallest node in the right subtree
while ((left = node->rb_left))
node = left;
// replace orginal node(old) by node
if (rb_parent(old)) {
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else {
root->rb_node = node;
}
child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node);
// case: original node has no left child
if (parent == old) {
parent = node;
} else {
if (child)
rb_set_parent(child, parent);
parent->rb_left = child;
node->rb_right = old->rb_right;
rb_set_parent(old->rb_right, node);
}
node->rb_parent_color = old->rb_parent_color;
node->rb_left = old->rb_left;
rb_set_parent(old->rb_left, node);
goto color;
}
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent) {
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
} else {
root->rb_node = child;
}
color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
}
刪除節點的再平衡
if/else一樣是判斷是左節點還是右節點,看一邊即可
兄弟節點other是紅色,對親代節左旋轉並且重新著色
other->黑色
parent->紅色
other節點的左節點是紅色,右節點是黑色
對other右旋轉並且重新著色,改變other指標指到l
結束上述條件判斷後
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_left);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
就是把parent左旋轉並且顏色對調
static void __rb_erase_color(struct rb_node *node,
struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other;
while ((!node || rb_is_black(node)) && node != root->rb_node) {
if (parent->rb_left == node) {
other = parent->rb_right;
if (rb_is_red(other)) {
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right))) {
rb_set_red(other);
node = parent;
parent = rb_parent(node);
} else {
if (!other->rb_right || rb_is_black(other->rb_right)) {
rb_set_black(other->rb_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_right);
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
} else {
other = parent->rb_left;
if (rb_is_red(other)) {
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right))) {
rb_set_red(other);
node = parent;
parent = rb_parent(node);
} else {
if (!other->rb_left || rb_is_black(other->rb_left)) {
rb_set_black(other->rb_right);
rb_set_red(other);
__rb_rotate_left(other, root);
other = parent->rb_left;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_left);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
rb_set_black(node);
}
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up