数据结构与算法 :红黑树 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

相关文章
相关标签/搜索