數據結構與算法 :紅黑樹 C語言實現

花了好幾天的業餘時間,看文章,總算是用C實現了一遍紅黑樹,主要仍是本身C語言水平不夠高,調試斷點浪費了很多時間,閒話少說node

1. 紅黑樹結構體

//這裏偷懶就應0表明黑色,1表明紅色了
typedef struct RBTreeNode {
    int data; //數據域
    int color; //0黑色 1紅色
    struct RBTreeNode *parent;//父親結點
    struct RBTreeNode *left;  //左子結點
    struct RBTreeNode *right; //右子結點
} RBTreeNode;

2. 前序遍歷

//這裏打印了節點的顏色和父節點
void preOrderTraverse(RBTreeNode *root)
{
    if (root != NULL)
    {        
        if (root->parent != NULL)
        {
            printf("%d color: %d parent:%d\n", root->data, root->color, root->parent->data);
        }else{
            printf("%d color: %d\n", root->data, root->color);
        }        
        preOrderTraverse(root->left);
        preOrderTraverse(root->right);
    }
}

3.1 左旋

跟AVL樹差很少,多了parent相關的操做測試

/**
 * 左旋
 *            parent                    parent
 *          8                         12
 *       4     12                  8     50  
 *           9    50      =>    4    9      70
 *                   70                      
 */
RBTreeNode *left_rotation(RBTreeNode *root)
{
    struct RBTreeNode *new_root;
    new_root         = root->right;
    root->right      = new_root->left;
    //將9的父親設置爲老的root 即8
    if (new_root->left != NULL)
    {
        new_root->left->parent = root;
    }
    //新root的parent即老parent
    new_root->parent = root->parent;
    //而後處理老root的parent
    if (root->parent == NULL)
    {
        //老root是根節點
        new_root->parent = NULL;
    }else{
        //判斷父親左右
        if (new_root->parent->left == root)
        {
            new_root->parent->left = new_root;
        }else{
            new_root->parent->right = new_root;
        }
    }
    root->parent = new_root;
    new_root->left   = root;
    return new_root;
}

3.2 右旋

/**
 * 右旋
 *          8                  4
 *       4     12           2     8
 *    2    6         =>  1      6   12
 * 1                                
 */
RBTreeNode *right_rotation(RBTreeNode *root)
{
    struct RBTreeNode *new_root;
    new_root         = root->left;
    root->left      = new_root->right;
    
    //將6的父親設置爲老的root 即8
    if (new_root->right != NULL)
    {
        new_root->right->parent = root;
    }
    //新root的parent即老parent
    new_root->parent = root->parent;
    
    //而後處理老root的parent
    if (root->parent == NULL)
    {
        //老root是根節點
        new_root->parent = NULL;
    }else{
        //判斷父親左右
        if (new_root->parent->left == root)
        {
            new_root->parent->left = new_root;
        }else{
            new_root->parent->right = new_root;
        }
    }
    
    new_root->right   = root;
    root->parent = new_root;
    // printf("***本身right_rotation***:  \n");
    // printfNode(new_root);
    // printf("***左***:  \n");
    // printfNode(new_root->left);
    // printf("***右***:  \n");
    // printfNode(new_root->right);
    return new_root;
}

3.3 代碼圖解

/**
 * 1.插入的只有一個根節點
 * 
 *         8(R)  => 8(B)
 * 
 * 2.1父節點是黑色,啥也不用幹
 *           8(B)
 *         /          =>   不變
 *      4(R)
 *
 * 2.2 父節點是紅色,祖父必定是黑色啦,看叔叔是啥顏色
 *
 * 2.2.1 父節點是祖父節點的左節點
 *
 *     2.2.1.1若是叔叔也是紅色 
 *            將父節點,叔節點設爲黑色,將祖父節點設爲紅色,將祖父節點設爲「當前節點」(紅色節點);即,以後遞歸繼續對「當前節點」進行操做
 *
 *                  8(B)              8(R)               8(B)
 *                 /    \            /    \             /    \ 
 *               4(R)   12(R)  =>  4(B)   12(B)   =>  4(B)   12(B)
 *               /                 /                   /
 *             2(R)              2(R)                2(R)
 *     
 *     2.2.1.2若是叔叔不存在或是黑色
 *           2.2.1.2.1新節點在左子樹
 *                    父節點設爲黑色,將祖父節點設爲紅色,對祖父節點右旋
 *
 *                  8(B)                 8(R)                         8(B)
 *                 /    \     着色       /    \        對4右旋     /    \ 
 *               4(B)  12(B)   =>      4(R)   12(B)       =>      2(B)   12(B)
 *               /                     /                          /  \
 *             2(R)                  2(B)                     1(R)   4(R)
 *             /                     /
 *           1(R)                  1(R)
 *           
 *           2.2.1.2.2新節點在右子樹
 *                    root與父節點交換 並把父節點設爲新root的左節點,即轉化爲2.2.1.2.1,處理如上
 *
 *                  8(B)                 8(B)                  8(B)                         8(B)
 *                 /    \     交換       /    \       着色     /    \         對4右旋     /    \ 
 *               4(B)  12(B)   =>      4(B)   12(B)   =>    4(R)   12(B)        =>      3(B)   12(B)
 *               /                     /                    /                           /  \
 *             2(R)                  3(R)                 3(B)                        2(R)  4(R)
 *                \                  /                    /
 *                3(R)             2(R)                 2(R)
 *
 *
 *
 * 2.2.2 父節點是祖父節點的右節點
 *     2.2.2.1若是叔叔也是紅色
 *             將父節點,叔節點設爲黑色,將祖父節點設爲紅色,將祖父節點設爲「當前節點」(紅色節點);即,以後遞歸繼續對「當前節點」進行操做
 *
 *                  8(B)              8(R)               8(B)
 *                 /    \            /    \             /    \ 
 *               4(R)   12(R)  =>  4(B)   12(B)   =>  4(B)   12(B)
 *                        \                 \                   \
 *                        20(R)              20(R)               20(R)
 *
 *     2.2.2.2若是叔叔不存在或是黑色(這裏的繪圖簡化些,其實都同樣的)
 *             2.2.2.2.1新節點在左子樹
 *                 root與父節點交換 並把父節點設爲新root的右節點,即轉化爲2.2.2.2.2
 *                 8(B)                  8(B)                8(R)                   10(B)
 *                    \         交換        \         着色      \        對8右旋     /   \ 
 *                    12(R)     =>          10(R)      =>       10(B)     =>      8(R)  12(R)
 *                    /                       \                   \
 *                  10(R)                     12(R)               12(R)
 *
 *             2.2.2.2.2新節點在右子樹
 *                 將父節點設爲黑色 將祖父節點設爲紅色 左旋
 *                 
 *                   8(B)                     8(R)                   12(B)
 *                     \         着色           \        對8左旋     /    \ 
 *                     12(B)      =>           12(B)       =>      8(R)  20(R)
 *                        \                      \                         
 *                        20(R)                  20(R)                     
 *
 * 
 */

4. 自平衡

RBTreeNode *rebalance3(RBTreeNode *root, RBTreeNode *rootNode)//返回新的根節點
{
    //1 插入根節點,只需置黑便可
    if (root->parent == NULL)
    {
        root->color = 0;
    }
    //2 有父節點
    if (root->parent != NULL)
    {   
        //2.1 父節點是黑色,啥也不用幹
        if (root->parent->color == 0)
        {
            //do nothing
        }else{
        //2.2 父節點是紅色,祖父必定是黑色啦,看叔叔是啥顏色
            RBTreeNode *parent, *gparent, *uncle;
            parent = root->parent;
            gparent = root->parent->parent;
            int return_flag = 0;
            if (gparent == rootNode)
            {
                return_flag = 1;
            }
            //先判斷父節點是祖父節點的左節點仍是右節點,即叔叔節點是啥
            //2.2.1 父節點是祖父節點的左節點
            if (parent == gparent->left)
            {
                uncle = gparent->right;
                //2.2.1.1若是叔叔也是紅色
                if (uncle != NULL && uncle->color == 1)
                {
                    //1.將父節點設爲黑色
                    parent->color = 0;
                    //2.將叔節點設爲黑色
                    uncle->color = 0;
                    //3.將祖父節點設爲紅色
                    gparent->color = 1;
                    //4.將祖父節點設爲「當前節點」(紅色節點);即,以後繼續對「當前節點」進行操做
                    
                    return rebalance3(gparent, rootNode);
                }else{
                //2.2.1.2若是叔叔黑色 或不存在
                    //2.2.1.2.1 root是左節點
                    if (root == parent->left)
                    {
                        //1.將父節點設爲黑色
                        parent->color = 0;
                        //2.將祖父節點設爲紅色
                        gparent->color = 1;
                        gparent = right_rotation(gparent);
                    }else{
                    //2.2.1.2.2 root是右節點
                        //1.root與父節點交換 並把父節點設爲新root的左節點,即轉化爲2.2.1.2.1
                        gparent->left = root;                       

                        root->parent = gparent;
                        root->left = parent;

                        parent->parent = root;
                        parent->right = NULL;

                        return rebalance3(parent, rootNode);
                    }
                }
            }else{
            //2.2.2 父節點是祖父節點的右節點
                uncle = gparent->left;
                //2.2.2.1若是叔叔也是紅色
                if (uncle != NULL && uncle->color == 1)
                {
                    //1.將父節點設爲黑色
                    parent->color = 0;
                    //2.將叔節點設爲黑色
                    uncle->color = 0;
                    //3.將祖父節點設爲紅色
                    gparent->color = 1;
                    //4.將祖父節點設爲「當前節點」(紅色節點);即,以後繼續對「當前節點」進行操做
                    return rebalance3(gparent, rootNode);
                }else{
                //2.2.2.2若是叔叔黑色 或不存在
                    //2.2.2.2.1 root是左節點
                    if (root == parent->left)
                    {
                        //1.root與父節點交換 並把父節點設爲新root的左節點,即轉化爲2.2.2.2.2
                        gparent->right = root;
                        root->parent = gparent;
                        root->right = parent;
                        parent->parent = root;   
                        parent->left = NULL;
                        return rebalance3(parent, rootNode);
                    }else{
                    //2.2.2.2.2 root是右節點                        
                        //1.將父節點設爲黑色
                        parent->color = 0;
                        //2.將祖父節點設爲紅色
                        gparent->color = 1;

                        gparent = left_rotation(gparent);
                    }
                }
            }
            if (return_flag == 1)
            {
                return gparent;
            }
        }
    }
    return rootNode;
}

5.1 插入(未平衡)

RBTreeNode *getNode(int data, RBTreeNode *parent)
{
    struct RBTreeNode *node;
    node = (struct RBTreeNode *)malloc(sizeof(struct RBTreeNode));
    if (node == NULL)
    {
        printf("malloc error \n");
        return NULL;
    }
    node->data  = data;
    node->parent= parent;
    node->color = 1;
    node->right = NULL;
    node->left  = NULL;
    if (parent == NULL)
    {
        node->color = 0;
    }
    RBTreeEndNode = node;
    return node;
}
RBTreeNode *insert(RBTreeNode *root, int data, RBTreeNode *parent)
{
    if (NULL == root)
    {
        return getNode(data, parent);
    }
    if (data >= root->data)
    {
        root->right  = insert(root->right, data, root);
    }else{
        root->left   = insert(root->left, data, root);
    }
    return root;
}

5.2 插入(平衡)

RBTreeNode *inserRB(RBTreeNode *root, int data, RBTreeNode *parent)
{
    root = insert(root,data,parent);
    return rebalance3(RBTreeEndNode,root);
}

6 測試紅黑樹構建

int main()
{ 
    struct RBTreeNode *node;
    
    //2.2.1.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 2, NULL);
    printf("***2.2.1.1 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //2.2.1.2.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 2, NULL);
    node = inserRB(node, 1, NULL);
    printf("***2.2.1.2.1 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //2.2.1.2.2 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 2, NULL);
    node = inserRB(node, 3, NULL);
    printf("***2.2.1.2.2 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //2.2.2.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 20, NULL);
    printf("***2.2.2.1 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //2.2.2.2.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    printf("***2.2.2.2.1 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //2.2.2.2.2 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 20, NULL);
    printf("***2.2.2.2.2 測試用例 前序***:  \n");
    preOrderTraverse(node);
}

測試結果:
imagespa

7 紅黑樹刪除圖解

*刪除
 *
 *1.沒有左右節點
 *
 * 1.1被刪除節點是紅色,直接刪除便可
 *
 *      8(B)              8(B)
 *      /         =>  
 *    4(R)
 *    
 * 1.2被刪除節點是黑色,破壞了平衡性 須要從新平衡
 * 
 *     1.2.1被刪除節點在父節點的左數上
 *     
 *          1.2.1.1兄弟節點是黑色,
 *          
 *                  1.2.1.1.1 兄弟節點是黑色,且有一個右節點,右節點必然是紅色
 *                   parent                                    parent                      parent
 *                    |                                          |                              |
 *                    8(可紅可黑)     把父節點顏色賦值給14        8(可紅可黑)                     12(B)
 *                   /  \               刪除4 着色                \             對8左旋        /    \         
 *                 4(B) 12(B)               =>                   12(B)           =>   8(可紅可黑)  14(可紅可黑)   最終保持黑色節點數量依舊是1或者2個
 *                       \                                         \
 *                      14(R)必然是紅色                           14(可紅可黑,8是啥色 這裏就啥色,下同)
 *                  
 *                  1.2.1.1.2 兄弟節點是黑色,且有一個左節點,左節點必然是紅色
 *                   parent                                        parent                          parent
 *                     |                把父節點顏色賦值給兄弟節點     |                                |
 *                     8(可紅可黑)        相似插入時候如右圖 兄左置黑 8(可紅可黑)                       10(B)
 *                     /  \             刪除4 着色 轉變爲1.2.1.1       \             對8左旋          /    \         
 *                   4(B) 12(B)               =>                       10(B)           =>    8(可紅可黑)  12(可紅可黑)   最終保持黑色節點數量依舊是1或者2個
 *                        /                                             \
 *                      10(R)必然是紅色                                  12(可紅可黑)
 *
 *                  1.2.1.1.3 兄弟節點是黑色,且有倆節點,必然都是紅色
 *                      parent                                        parent                          parent
 *                        |                把父節點顏色賦值給兄弟節點     |                                |
 *                      8(可紅可黑)         把兄弟節點的右節點置黑       8(黑)                            12(可紅可黑)
 *                      /  \               把父節點置黑  刪除4            \                   對8左旋    /    \         
 *                    4(B) 12(B)               =>                        12(可紅可黑)           =>   8(B)  14(B)   最終保持黑色節點數量依舊是1或者2個
 *                          / \                                          /  \                          \
 *                      10(R)  14(R)必然都是紅色                       10(R) 14(B)                      10(R)
 *                  1.2.1.1.4 兄弟節點是黑色,且沒有節點 黑色路徑必然要-1了 遞歸
 *                  ps:這個存疑 1.理論上插入時候每次自平衡不應有這個狀況;2.即便有這個狀況,那刪除自身後,也不影響平衡啊
 *
 *                      (此處例外,不是刪除4,而是刪除10節點)
 *                      parent                                           parent                            parent
 *                        |                                                 |                                |
 *                      8(可紅可黑)         刪除10(黑)                     8(可紅可黑)                        8(可紅可黑)
 *                      /  \               把14置紅 下一步rebalance        /  \           rebalance         /    \         
 *                    4(B) 12(R)               =>                      4(B) 12(R)           =>           4(B)   12(B)   最終保持黑色節點數量依舊是1或者2個
 *                          / \                                               \                                   \
 *                      10(B)  14(B)                                           14(R)                              14(R)
 *                      
 *           1.2.1.2兄弟節點是紅色
 *                  1.2.1.2.1 兄弟節點是紅色,父節點必定是黑色,它必定有倆黑色子節點
 *                  parent                                    parent                      parent
 *                    |                                          |                              |
 *                   8(B)        兄弟節點置黑,兄弟左節點置紅      8(B)                           12(B)
 *                   /  \               刪除4 着色                 \             對8左旋        /    \         
 *                 4(B) 12(R)               =>                    12(B)           =>          8(B)  14(B)   最終保持黑色節點數量依舊是2個
 *                      / \                                        /  \                        \
 *                   10(B) 14(B)必然是黑色                       10(R)  14(B)                  10(R)
 *                   
 *    1.2.2被刪除節點在父節點的右數上
 *    
 *          1.2.2.1兄弟節點是黑色
 *          
 *                  1.2.2.1.1 兄弟節點是黑色,且有一個左節點,左節點必然是紅色 跟 1.2.1.1.1互爲鏡像
 *                     parent                                    parent                         parent
 *                      |                                          |                              |
 *                      8(可紅可黑)     把父節點顏色賦值給3        8(可紅可黑)                     4(B)
 *                     /  \               刪除12 着色            /           對8右旋            /    \         
 *                   4(B) 12(B)               =>              4(B)           =>          3(可紅可黑)  8(可紅可黑)   最終保持黑色節點數量依舊是1或者2個
 *                   /                                         /
 *                 3(R)必然是紅色                           3(可紅可黑)
 *                  
 *                  1.2.2.1.2 兄弟節點是黑色,且有一個左節點,左節點必然是紅色
 *                   parent                                        parent                          parent
 *                     |                把父節點顏色賦值給兄弟節點     |                                |
 *                     8(可紅可黑)        相似插入時候如右圖 兄右置黑 8(可紅可黑)                      5(B)
 *                     /  \             刪除12 着色 轉變爲1.2.2.1.1   /             對8右旋          /    \         
 *                   4(B) 12(B)               =>                   5(B)           =>      4(可紅可黑)    8(可紅可黑)   最終保持黑色節點數量依舊是1或者2個
 *                      \                                          /
 *                      5(R)必然是紅色                            4(可紅可黑)
 *
 *                  1.2.2.1.3 兄弟節點是黑色,且有倆節點,必然都是紅色
 *                      parent                                        parent                          parent
 *                        |                把父節點顏色賦值給兄弟節點     |                                |
 *                      8(可紅可黑)         把兄弟節點的左節點置黑       8(B)                            4(可紅可黑)
 *                      /  \               把父節點置黑  刪除12        /                對8右旋         /    \         
 *                    4(B) 12(B)               =>                  4(可紅可黑)           =>          1(B)   8(B)   最終保持黑色節點數量依舊是1或者2個
 *                    / \                                          /  \                                   /
 *                 1(R)  5(R)必然都是紅色                         1(R)  5(R)                             5(R)
 *                 
 *                  1.2.2.1.4 兄弟節點是黑色,且沒有節點 黑色路徑必然要-1了 遞歸
 *                  ps:這個存疑 1.理論上插入時候每次自平衡不應有這個狀況;2.即便有這個狀況,那刪除自身後,也不影響平衡啊
 *
 *                      (此處例外,不是刪除12,而是刪除5節點)
 *                      parent                                           parent                            parent
 *                        |                                                 |                                |
 *                      8(可紅可黑)         刪除5(黑)                     8(可紅可黑)                        8(可紅可黑)
 *                      /  \               把1置紅 下一步rebalance        /  \           rebalance         /    \         
 *                    4(R) 12(B)               =>                      4(R) 12(B)           =>           4(B)   12(B)   最終保持黑色節點數量依舊是1或者2個
 *                    / \                                              /                                /
 *                 1(B)  5(B)必然都是黑色                             1(R)                             1(R)
 *                      
 *           1.2.2.2兄弟節點是紅色
 *                  1.2.2.2.1 兄弟節點是紅色,父節點必定是黑色,它必定有倆黑色子節點
 *                  parent                                    parent                      parent
 *                    |                                          |                           |
 *                   8(B)        兄弟節點置黑,兄弟右節點置紅      8(B)                         4(B)
 *                   /  \               刪除12 着色              /         對8右左旋        /    \         
 *                 4(R) 12(B)               =>               4(B)           =>          1(B)  8(B)   最終保持黑色節點數量依舊是2個
 *                / \                                        /  \                              /
 *              1(B) 5(B)必然是黑色                       1(B)  5(R)                          5(R)
 *
 *2. 只有左節點
 *                  parent                               parent
 *                    |                                     |
 *                   8(可紅可黑)         1的值賦給4          8(可紅可黑)
 *                   /  \               刪除1 着色        /    \         
 *                 4(B) 12(B)               =>         1(B)  12(B)   最終保持黑色節點數量依舊是2個
 *                /                                                                      
 *              1(R)  
 *4. 只有右節點 同上
 *5. 左右都有
 *      //後繼節點:刪除節點的右子樹中的最小節點,即右子樹中最左節點。
 *      //前驅節點:刪除節點的左子樹中最大節點,即左子樹中最右節點。
 *      使用前驅or後繼代替當前刪除節點,而後刪除替代結點,把情形轉化爲1,2,3的狀況
 */

8 紅黑樹刪除代碼

RBTreeNode *FindMin(RBTreeNode *root)
{
    if (NULL == root)
    {
        return NULL;
    }
    if (root->left == NULL)
    {
        return root;
    }else{
        return FindMin(root->left);
    }
}
RBTreeNode *Delete(RBTreeNode *root, int target, RBTreeNode *rootNode)
{
    if (NULL == root)
    {
        return NULL;
    }
    if (target > root->data)
    {
        rootNode = Delete(root->right, target, rootNode);
    }else if(target < root->data){
        rootNode  = Delete(root->left, target, rootNode);
    }else{        
        //根節點
        if (root->parent == NULL)
        {
            return NULL;//刪除自身
        }
        
        RBTreeNode *parent, *brother;
        parent = root->parent;

        int root_flag = 0;
        if (parent == rootNode)
        {
            root_flag = 1;
        }
        //1.沒有左右節點
        if (root->left == NULL && root->right == NULL)
        {
            //1.1被刪除節點是紅色,直接刪除便可
            if (root->color == 1)
            {
                if (root == parent->left){
                    parent->left = NULL;
                }else{
                    parent->right = NULL;
                }
                root = NULL;//刪除自身
            }else{
            //1.2被刪除節點是黑色,必定右兄弟節點 破壞了平衡性 須要從新平衡
                //1.2.1被刪除節點在父節點的左數上
                if (root == parent->left)
                {
                    root = NULL;
                    parent->left = NULL;//刪除自身
                    brother = parent->right;
                    //1.2.1.1兄弟節點是黑色
                    if (brother->color == 0)
                    {
                        //1.2.1.1.1 兄弟節點是黑色,且有一個右節點,右節點必然是紅色
                        if (brother->right != NULL && brother->left == NULL)
                        {
                            //把父親顏色賦值給兄弟節點的右節點
                            brother->right->color = parent->color;
                            parent = left_rotation(parent);
                        }else if (brother->right == NULL && brother->left != NULL)
                        //1.2.1.1.2 兄弟節點是黑色,且有一個左節點,左節點必然是紅色
                        {
                            //把父親顏色賦值給兄弟節點
                            brother->color = parent->color;
                            parent->right  = brother->left;

                            brother->parent = brother->left;
                            
                            brother->left->parent = parent;
                            brother->left->right  = brother;
                            brother->left   = NULL;

                            parent = left_rotation(parent);
                        }else if (brother->right != NULL && brother->left != NULL)
                        {
                        //1.2.1.1.3 兄弟節點是黑色,且有倆節點,必然都是紅色
                            //把父親顏色賦值給兄弟節點
                            brother->color = parent->color;
                            //把兄弟節點的右節點置黑
                            //把父節點置黑
                            brother->right->color = 0;
                            parent->color = 0;

                            parent = left_rotation(parent);
                        }else{
                        //1.2.1.1.4 兄弟節點是黑色,且沒有節點 黑色路徑必然要-1了 遞歸
                        //ps:這個存疑 1.理論上插入時候每次自平衡不應有這個狀況;2.即便有這個狀況,那刪除自身後,也不影響平衡啊
                            //parent->right->color = 1;
                            //return rebalance3(parent->right,rootNode);
                        }
                    }else{
                    //1.2.1.2兄弟節點是紅色,父節點必定是黑色,它必定有倆黑色子節點
                        //兄弟節點置黑,兄弟左節點置紅
                        brother->color = 0;
                        brother->left->color  = 1;
                        parent = left_rotation(parent);
                    }
                }else{
                //1.2.2被刪除節點在父節點的右數上
                    root = NULL;
                    parent->right = NULL;//刪除自身
                    brother = parent->left;
                    //1.2.2.1 兄弟節點是黑色
                    if (brother->color == 0)
                    {
                        //1.2.2.1.1 兄弟節點是黑色,且有一個左節點,左節點必然是紅色 跟1.2.1.1.1是鏡像關係
                        if (brother->right == NULL && brother->left != NULL)
                        {
                            //把父親顏色賦值給兄弟節點的左節點
                            brother->left->color = parent->color;
                            parent = right_rotation(parent);
                        }else if(brother->right != NULL && brother->left == NULL)
                        //1.2.2.1.2 兄弟節點是黑色,且有一個右節點,右節點必然是紅色 跟1.2.1.1.2是鏡像關係
                        {
                            parent->left = brother->right;                          
                            brother->color = parent->color;
                            brother->parent = brother->right;

                            brother->right->parent = parent;
                            brother->right->left   = brother;
                            brother->right  = NULL;
                            parent = right_rotation(parent);
                        }else if(brother->right != NULL && brother->left != NULL)
                        //1.2.2.1.3 兄弟節點是黑色,且有倆節點,必然都是紅色 跟1.2.1.1.3是鏡像關係
                        {
                            brother->left->color = 0;                          
                            brother->color = parent->color;
                            parent = right_rotation(parent);
                        }else{
                        //1.2.2.1.4 兄弟節點是黑色,且沒有節點 黑色路徑必然要-1了 遞歸
                        //ps:這個存疑 1.理論上插入時候每次自平衡不應有這個狀況;2.即便有這個狀況,那刪除自身後,也不影響平衡啊
                            //do nothng
                            // parent->left->color = 1;
                            // return rebalance3(parent->left,rootNode);
                        }  
                    }else{
                    //1.2.2.2兄弟節點是紅色,父節點必定是黑色,它必定有倆黑色子節點
                        //兄弟節點置黑,兄弟右節點置紅
                        brother->color = 0;
                        brother->right->color  = 1;
                        parent = right_rotation(parent);
                    }
                }
            }
        }else if (root->left != NULL && root->right == NULL)
        //2.只有左節點 該左節點必然是紅色,那root必定是黑色,root值替換爲左節點的值,刪除左節點
        {
            root->data = root->left->data;
            root->left  = NULL;
        }else if (root->right != NULL && root->left == NULL)
        //3.只有右節點 該右節點必然是紅色,那root必定是黑色,root值替換爲右節點的值,刪除右節點
        {
            root->data = root->right->data;
            root->right  = NULL;
        }else{
        //4.左右都有的狀況
        //後繼節點:刪除節點的右子樹中的最小節點,即右子樹中最左節點。
        //前驅節點:刪除節點的左子樹中最大節點,即左子樹中最右節點。
            //4.1使用後繼節點做爲代替結點
            RBTreeNode *min = FindMin(root->right);
            root->data = min->data;
            rootNode  = Delete(min, min->data, rootNode);
        }
        if (root_flag == 1)
        {
            return parent;
        }
    }
    return rootNode;
}

* 刪除測試代碼

int main()
{ 
    struct RBTreeNode *node;

    //1.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = Delete(node, 4, node);
    printf("***1.1 測試用例 前序***:  \n");
    preOrderTraverse(node);
    
    //1.2.1.1.1 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 14, NULL);
    node = Delete(node, 4, node);
    printfNode(node);
    printf("***1.2.1.1.1 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //1.2.1.1.2 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    node = Delete(node, 4, node);
    printfNode(node);
    printf("***1.2.1.1.2 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //1.2.1.1.3 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    node = inserRB(node, 14, NULL);
    node = Delete(node, 4, node);
    printfNode(node);
    printf("***1.2.1.1.3 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //1.2.1.1.4 測試用例  存疑
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    node = inserRB(node, 14, NULL);
    //這裏須要特殊處理,由於8,4,12,10,14生成的紅黑樹不符合1.2.1.1.4的測試場景,處理後依然是紅黑樹
    //      8(B)                             8(B)                        
    //      /  \                 處理後      /  \                        
    //    4(B) 12(B)               =>     4(B) 12(R)               
    //         / \                              / \                 
    //      10(R)  14(R)                     10(B) 14(B)
    node->right->color = 1;
    node->right->right->color = 0;
    node->right->left->color = 0;
    node = Delete(node, 10, node);
    printf("***1.2.1.1.4 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //1.2.1.2.1 測試用例  存疑
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    node = inserRB(node, 14, NULL);
    //這裏須要特殊處理,由於8,4,12,10,14生成的紅黑樹不符合1.2.1.1.4的測試場景,處理後依然是紅黑樹
    //      8(B)                             8(B)                        
    //      /  \                 處理後      /  \                        
    //    4(B) 12(B)               =>     4(B) 12(R)               
    //         / \                              / \                 
    //      10(R)  14(R)                     10(B) 14(B)  
    node->right->color = 1;
    node->right->right->color = 0;
    node->right->left->color = 0;
    node = Delete(node, 4, node);
    printf("***1.2.1.2.1 測試用例 前序***:  \n");
    preOrderTraverse(node);
    

    //1.2.2.1.1 測試用例 跟1.2.1.1.1是鏡像關係
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 3, NULL);
    node = Delete(node, 12, node);
    printfNode(node);
    printf("***1.2.2.1.1 測試用例 前序***:  \n");
    preOrderTraverse(node);
     
    //1.2.2.1.2 測試用例 跟1.2.1.1.2是鏡像關係
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 5, NULL);
    node = Delete(node, 12, node);
    printfNode(node);
    printf("***1.2.2.1.1 測試用例 前序***:  \n");
    preOrderTraverse(node);
     

     
    //1.2.2.1.3 測試用例 跟1.2.1.1.2是鏡像關係
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 1, NULL);
    node = inserRB(node, 5, NULL);
    
    node = Delete(node, 12, node);
    printf("***1.2.2.1.3 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //1.2.2.1.4 測試用例 跟1.2.1.1.4是鏡像關係 存疑
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 1, NULL);
    node = inserRB(node, 5, NULL);
    node = Delete(node, 5, node);
    printf("***1.2.2.1.4 測試用例 前序***:  \n");
    preOrderTraverse(node);
     
    //1.2.2.2 測試用例 跟1.2.2.1是鏡像關係
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 1, NULL);
    node = inserRB(node, 5, NULL);
    //特殊處理
    node->left->color = 1;
    node->left->left->color = 0;
    node->left->right->color = 0;
    node = Delete(node, 12, node);
    printf("***1.2.2.1.4 測試用例 前序***:  \n");
    preOrderTraverse(node);
 
     
    //2 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 4, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 3, NULL);
    node = Delete(node, 4, node);
    printf("***2 測試用例 前序***:  \n");
    preOrderTraverse(node);

    //3 測試用例
    node = NULL;
    node = inserRB(node, 8, NULL);
    node = inserRB(node, 2, NULL);
    node = inserRB(node, 14, NULL);
    node = inserRB(node, 1, NULL);
    node = inserRB(node, 5, NULL);
    node = inserRB(node, 12, NULL);
    node = inserRB(node, 10, NULL);
    node = inserRB(node, 28, NULL);
    node = inserRB(node, 20, NULL);
    node = inserRB(node, 40, NULL);
    node = inserRB(node, 22, NULL);

    node = Delete(node, 20, node);
    printf("***3 測試用例 前序***:  \n");
    preOrderTraverse(node);
}

結果

image

相關文章
相關標籤/搜索