紅黑樹
紅黑樹的規則:
- 每個節點非黑即紅。
- 根結點是黑色。
- 葉結點 (NIL) 是黑色。
- 如果一個結點是紅色, 則它的兩個子節點都是黑色的。
- 從根結點出發到所有葉結點的路徑上, 均包含相同。
調整策略:
- 插入調整站到 祖父節點 觀察。
- 刪除調整站在 父節點 觀察。
- 插入和刪除的情況一共五種。
優勢:最短路徑 與 最長路徑 長度至多差一倍。
插入操作:
首先我們明確插入節點 x 必將預先設置爲紅色,這樣保證了 規則 5 的成立。
當插入的新結點 x 的父結點是紅色時,需要從新結點出發向上進行調整。
1)x 的叔父節點爲紅色
此時 x 的祖父節點一定是黑色,我們直接將祖父節點改爲紅色,父節點和叔父節點均改爲黑色即可。
調整前:
調整後:
2)x 的叔父節點爲黑色,而且 x 是一個右孩子。
觀察 x 對於其祖父節點在其左子樹還是右子樹上,如若在其左子樹,則當前屬於LR型。
對於 x 的父節點進行左小旋,這樣保證了$ x $ 的左子樹上每條路徑黑色節點不變。
變換結束後,x 的叔父節點仍爲黑色,父節點仍爲紅色,不過此時 x 已經成爲了一個左孩子,按第三種情況 進行調整。
調整前:
調整後:
3)x 的叔父節點爲黑色,而且 x 是一個左孩子。
觀察 x 對於其祖父節點在其左子樹還是右子樹上,如若在其左子樹,則當前屬於LL型。
將 x 的父節點改爲黑色,x 的祖父節點改爲紅色,然後對於 x 的父節點進行一次右大旋。
這時 x 的父結點爲黑色,不需要再向上迭代調整了。
調整前:
調整後:
這裏我們只討論了LL型與LR型的調整策略,對於RR型與RL型調整策略是對稱的。
刪除操作:
在討論二叉排序樹刪除節點,在刪除度數爲2的節點時,我們將其轉化爲度爲1的節點刪除,我們在對於紅黑樹刪除操作時也該是如此。
如果要刪除的節點爲紅色,其父節點與子節點應該均爲黑色,直接將子節點連到其父節點即可。因爲他的顏色是紅色,所以直接刪除他不會破壞規則5。
如果要刪除的節點爲黑色,其子節點爲紅色,直接將子節點替換上來,然後改爲黑色即可。
當待刪除節點 x 與子節點均爲黑色時:
首先我們將待刪除節點 x 的子節點替換上來,將其添加一層黑色 (雙重黑色)。
具有 “雙重黑色” 的節點,在計算路徑上黑色節點數量時,經過 x 要計算兩次。
1)具有 “雙重黑色”的節點 x 兄弟節點爲紅色。
將 x 的兄弟節點改爲黑色,父節點改爲紅色。如若 x 是一個右孩子,那麼對於 x 的父節點進行一個右旋操作。
此時,對於 x 兄弟節點變爲了黑色,可以按照接下來幾種情況情形處理。
調整前:
調整後:
2)待刪除節點 x 的兄弟節點爲黑色,兄弟節點的兩個孩子也均爲黑色。
此時我們將 $x$ 的兄弟節點改爲紅色,然後 $x$ 褪去一層黑色,爲 $x$ 的父節點加一層黑色。
接下來我們將 x 的父節點作爲 x 繼續向上調整。
調整前:
調整後:
3)待刪除節點 x 的兄弟節點爲黑色,兄弟節點的左孩子爲紅色,右孩子爲黑色。
此時我們交換其兄弟節點與其左孩子的顏色,然後對於其兄弟節點進行右旋操作。屬於RL型。
現在兄弟節點的右孩子爲紅色了(RR型),我們繼續按照第四種情況進行調整。
調整前:
調整後:
4)待刪除節點 x 的兄弟節點爲黑色,兄弟節點的左孩子爲黑色,右孩子爲紅色。
將兄弟節點的父節點與右孩子從紅色改爲黑色,然後對於 x 的父節點進行一次左旋操作。使得 x 去掉一層黑色,此時以 x 的父節點 作爲 x 繼續向上調整。
調整前:
調整後:
#include <stdio.h>
#include <stdlib.h>
typedef struct RBNode {
int key, color; // 0 red, 1 black, 2 double black
struct RBNode *lchild, *rchild;
} RBNode;
RBNode *NIL;
RBNode *getNewNode(int key) {
RBNode *p = (RBNode *)malloc(sizeof(RBNode));
p->key = key;
p->color = 0;
p->lchild = p->rchild = NIL;
return p;
}
__attribute__((constructor)) void init_NIL() {
NIL = getNewNode(0);
NIL->color = 1;
NIL->lchild = NIL->rchild = NIL;
return ;
}
int hasRedChild(RBNode *node) {
return node->lchild->color == 0 || node->rchild->color == 0;
}
RBNode *left_rotate(RBNode *node) {
RBNode *temp = node->rchild;
node->rchild = temp->lchild;
temp->lchild = node;
return temp;
}
RBNode *right_rotate(RBNode *node) {
RBNode *temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
return temp;
}
RBNode *insert_maintain(RBNode *root) {
if (!hasRedChild(root)) return root;
if (root->lchild->color == 0 && root->rchild->color == 0) {
if (hasRedChild(root->lchild) || hasRedChild(root->rchild)) {
root->color = 0;
root->rchild->color = root->lchild->color = 1;
}
return root;
}
if (root->lchild->color == 0) {
if (!hasRedChild(root->lchild)) return root;
if (root->lchild->rchild->color == 0) {
root->lchild = left_rotate(root->lchild);
}
root = right_rotate(root);
} else {
if (!hasRedChild(root->rchild)) return root;
if (root->rchild->lchild->color == 0) {
root->rchild = right_rotate(root->rchild);
}
root = left_rotate(root);
}
root->color = 0;
root->lchild->color = root->rchild->color = 1;
return root;
}
RBNode *__insert(RBNode *root, int key) {
if (root == NIL || root == NULL) return getNewNode(key);
if (root->key == key) return root;
if (root->key < key) root->rchild = __insert(root->rchild, key);
else root->lchild = __insert(root->lchild, key);
return insert_maintain(root);
}
RBNode *insert(RBNode *root, int key) {
root = __insert(root, key);
root->color = 1;
return root;
}
RBNode *predecessor(RBNode *node) {
RBNode *temp = node->lchild;
while (temp->rchild != NIL) temp = temp->rchild;
return temp;
}
RBNode *erase_maintain(RBNode *root) {
if (root->lchild->color != 2 && root->rchild->color != 2) return root;
if (root->lchild->color == 0 || root->rchild->color == 0) {
root->color = 0;
if (root->lchild->color == 0) {
root->lchild->color = 1;
root = right_rotate(root);
root->rchild = erase_maintain(root->rchild);
} else {
root->rchild->color = 1;
root = left_rotate(root);
root->lchild = erase_maintain(root->lchild);
}
return root;
}
if (root->lchild->color == 2) {
if (!hasRedChild(root->rchild)) {
root->color += 1;
root->lchild->color = 1;
root->rchild->color = 0;
return root;
} else if (root->rchild->rchild->color == 1) {
root->rchild = right_rotate(root->rchild);
root->rchild->color = 1;
root->rchild->rchild->color = 0;
}
root->lchild->color = 1;
root = left_rotate(root);
root->color = root->lchild->color;
root->lchild->color = root->rchild->color = 1;
} else {
if (!hasRedChild(root->lchild)) {
root->color += 1;
root->rchild->color = 1;
root->lchild->color = 0;
return root;
} else if (root->lchild->lchild->color == 1) {
root->lchild = left_rotate(root->lchild);
root->lchild->color = 1;
root->lchild->lchild->color = 0;
}
root->rchild->color = 1;
root = right_rotate(root);
root->color = root->rchild->color;
root->lchild->color = root->rchild->color = 1;
}
return root;
}
RBNode *__erase(RBNode *root, int key) {
if (root == NULL || root == NIL) return NIL;
if (root->key < key) root->rchild = __erase(root->rchild, key);
else if (root->key > key) root->lchild = __erase(root->lchild, key);
else {
if (root->lchild == NIL && root->rchild == NIL) {
NIL->color += root->color;
free(root);
return NIL;
} else if (root->lchild == NIL || root->rchild == NIL) {
RBNode *temp = root->lchild == NIL ? root->rchild : root->lchild;
temp->color += root->color;
free(root);
return temp;
} else {
RBNode *temp = predecessor(root);
root->key = temp->key;
root->lchild = __erase(root->lchild, temp->key);
}
}
return erase_maintain(root);
}
RBNode *erase(RBNode *root, int key) {
root = __erase(root, key);
root->color = 1;
return root;
}
void clear(RBNode *root) {
if (root == NIL || root == NULL) return ;
clear(root->lchild);
clear(root->rchild);
free(root);
return ;
}
void output(RBNode *root) {
if (root == NIL) return ;
printf("(%d | %d, %d, %d)\n", root->color, root->key, root->lchild->key, root->rchild->key);
output(root->lchild);
output(root->rchild);
return ;
}
int main() {
int op, value;
RBNode *root = NIL;
while (scanf("%d%d", &op, &value) != EOF) {
switch (op) {
case 0:
printf("\ninsert %d\n", value);
root = insert(root, value); break;
case 1:
printf("\ndelete %d\n", value);
root = erase(root, value); break;
default: printf("error\n");
}
printf("----------\n");
output(root);
}
return 0;
}