# 紅黑樹移除節點時的問題與討論 [2022q1 第 18 週測驗題](https://hackmd.io/@sysprog/linux2022-quiz18) [rbtree-minimal](https://gist.github.com/jserv/3e87c957b577dc46c91d51f94159666c) * `node->__rb_parent_color` 紀錄 node 的 parent 及 node 的 color * 程式碼註解中小寫為 red node 大寫為 black node 帶有括號則兩種都有可能 e.g n N (n) * 以 kernel-scheduler Figure 3.3: data structure: red-black tree 的圖來看 ![](https://i.imgur.com/EBuBN08.png) 1. 假如 `__rb_erase` 的 node 是 2 的話會進到 case1 , 移除掉的節點是紅色 , 所以 rebalance 會是 NULL 不會進行 `__rb_erase_color` ; 反之 `__rb_erase` 移除的 node 是 31 的話 , 因為移除的 node 是黑色的 , 所以 rebalance 會是 node 34 , `__rb_erase_color` 會進到 if 的 case 4 並 break 出來 - [ ] `__rb_erase` ```c if (!tmp) { /* Case 1: node to erase has no more than 1 child (easy!) * * Note that if there is one child it must be red due to 5) * and node must be black due to 4). We adjust colors locally * so as to bypass __rb_erase_color() later on. */ pc = node->__rb_parent_color; parent = __rb_parent(pc); __rb_change_child(node, child, parent, root); if (child) { child->__rb_parent_color = pc; rebalance = NULL; } else // pc 裡紀錄的是 node 的顏色 rebalance = __rb_is_black(pc) ? parent : NULL; tmp = parent; } ``` 2. 假如 `__rb_erase` 的 node 是 7 的話會進到 else if 的 case1 , 會將 7 移除並將 2 變為 19 的 leftchild 且顏色改變為 7 的顏色 , rebalance 一樣是 NULL 所以也不會進行 `__rb_erase_color` - [ ] `__rb_erase` ```c else if (!child) { /* Still case 1, but this time the child is node->rb_left */ // 將 2 顏色改變為 7 的顏色 tmp->__rb_parent_color = pc = node->__rb_parent_color; parent = __rb_parent(pc); // 將從 19 移出的 7 變成 2 __rb_change_child(node, tmp, parent, root); rebalance = NULL; tmp = parent; } ``` 3. 假如 `__rb_erase` 的 node 是 19 的話會進到 Case 2 , rebalance 會是 node 25 , `__rb_erase_color` 會進到 `else` 的 case4 並 break 出去 4. 假如 `__rb_erase` 的 node 是 34 的話會進到 Case 3 , successor 為 49 且不是黑色所以 rebalance 為 NULL 5. `__rb_erase` * case1 : erase node 最多只有一個 child , 若只有一個 child 就不用 rebalance , 若沒有 child 則看 erase node 是否為黑色來決定要不要 rebalance , rebalance node 為 erase node 的 parent * case2 : erase node 有兩個 child 且 rightchild->left == NULL , erase node 會被 right child 取代 , 看 successor->right 是否存在或 successor 是否為黑色來決定要不要 rebalance , rebalance node 為 sucessor (即替換掉 erase node 的 node) * case3 : erase node 有兩個 child 且 rightchild->left != NULL , erase node 會被 right child 的 leftmost under node 取代 , 看 successor->right 是否存在或 successor 是否為黑色來決定要不要 rebalance , rebalance node 為 sucessor (即替換掉 erase node 的 node) 的 parent 6. `__rb_erase_color` * 會進到 if 的情況: * 迴圈第一次 parent->rb_right != null * 經過 Case 2 後且需要在 rebalance , node 為 node 的 parent 的 leftchild * 此時 sibling 為 parent->rightchild * case1: sibling 為紅色 * case2: sibling 為黑色,並且 sibling 兩個child 皆為黑色 * case3: sibling 為黑色,並且 sibling rightchild 為黑色,leftchild 為紅色 * case4: sibling 為黑色,並且 sibling rightchild 為紅色 * 會進到 else 的情況: * 迴圈第一次 parent->rb_right == null , 也就是 rebalance node 沒有 rightchild 的情況 (e.g 上面舉例的 19) * 經過 Case 2 後且需要在 rebalance , node 為 node 的 parent 的 rightchild * 此時 sibling 為 parent->leftchild * case1: sibling 為紅色 * case2: sibling 為黑色,並且 sibling 兩個 child 皆為黑色 * case3: sibling 為黑色,並且 sibling leftchild 為黑色,rightchild 為紅色 * case4: sibling 為黑色,並且 sibling leftchild 為紅色 7. 假如 `__rb_erase` 的 node 是 27 , 因為兩個 child 都有且 rightchild->left != NULL , 所以進到 Case 3 , successor 為 rightchild 的 leftmost under node(31) 並取代 erase node(27), 因 successor->right 不存在且 successor 為黑色要進行 rebalance , rebalance node 為 successor 的 parent(34) , 並傳入 `__rb_erase_color` , 因 rightchild 存在會進入 if statement , sibling 為黑色 65 又 sibling 的兩個 child 皆為紅色所以只會進到 case4 , 並完成修正 參考資料: https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/743044/ http://alrightchiu.github.io/SecondRound/red-black-tree-deleteshan-chu-zi-liao-yu-fixupxiu-zheng.html