我的紅黑樹學習筆記

紅黑樹


紅黑樹的規則:

  1. 每個節點非黑即紅。
  2. 根結點是黑色。
  3. 葉結點 (NIL) 是黑色。
  4. 如果一個結點是紅色, 則它的兩個子節點都是黑色的。
  5. 從根結點出發到所有葉結點的路徑上, 均包含相同。

調整策略:

  1. 插入調整站到 祖父節點 觀察。
  2. 刪除調整站在 父節點 觀察。
  3. 插入和刪除的情況一共五種。

優勢:最短路徑 與 最長路徑 長度至多差一倍。


插入操作:

首先我們明確插入節點 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章