红黑树插入 C语言实现

红黑树插入 C语言实现

推荐一个红黑树可视化网站: https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

红黑树插入,按照 排序二叉树规则插入即可,只不过插入后需要根据周边的节点来判断是否满足红黑树平衡,若不满足,需要进行 染色 或者 旋转修复。

博客后面提供插入完整代码

1. 什么是红黑树

红黑树是一种自平衡二叉查找树,巴拉巴拉--- , 请注意前提,是一颗二叉查找树

关于二叉查找树: https://baike.baidu.com/item/二叉排序树/10905079?fromtitle=二叉查找树&fromid=7077965&fr=aladdin

2. 红黑树概念

  • 每个节点要么是红色,要么是黑色
  • 根节点和叶节点是黑色的(红黑树的叶节点是NULL LEAF,默认NULL节点为黑色)
  • 如果一个节点是红色,那么它的孩子是黑色的(不允许连续2个红节点,但是允许2个连续的黑节点)
  • 任意节点到叶节点的树链中包含相同数量的黑节点

红黑树图示

image

3. 红黑树插入后判断是否平衡以及何种操作

1. 判断是否平衡

  • 若插入节点父节点为黑节点,则为平衡,无需修复。

  • 若插入节点父节点为红色,叔叔节点为红色,则需要进行染色修复。

  • 若插入节点父节点为红色,叔叔节点为黑色,则需要进行旋转。

2. 图示

ps: 黄色节点为 新插入节点,一般默认新插入节点颜色为红色!

1. 被插入节点父节点为黑色,无需进行修复

image

2. 被插入节点父节点为红色,叔叔节点为红色,需要进行染色修复

image

3. 被插入节点父节点为红色,叔叔节点为黑色(红黑树叶子节点都为黑色),需要进行旋转操作

image

3. 测试代码实现

先看结论,再看核心和具体函数代码

3.1 插入是否需要修复结论

  • 图示第一种情况

image

代码

int main() {
        TreeNode *root_160 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_85 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_240 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_260 = (TreeNode *)malloc(sizeof(TreeNode));

        root_160->data = 160; root_160->color = BLACK;
        node_85->data = 85; node_85->color = BLACK;
        node_240->data = 240; node_240->color = BLACK;
        node_260->data = 260; node_260->color = RED;

        root_160->left = node_85;
        root_160->right = node_240;
        node_240->right = node_260;

        InsertFixup1(&root_160,node_260);
        return 0;
}

​ 执行结果

# gcc RedBlackTreeInsert.c -w -g
# ./a.out 
插入数据:260
无需进行修复
# 
  • 图示第二种情况

image

代码

int main() {
        TreeNode *root_160 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_85 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_240 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_260 = (TreeNode *)malloc(sizeof(TreeNode));

        root_160->data = 160; root_160->color = BLACK;
        node_85->data = 85; node_85->color = RED;
        node_240->data = 240; node_240->color = RED;
        node_260->data = 260; node_260->color = RED;

        root_160->left = node_85;
        root_160->right = node_240;
        node_240->right = node_260;

        InsertFixup1(&root_160,node_260);
        return 0;
}

执行结果

# gcc RedBlackTreeInsert.c -w -g
# ./a.out 
插入数据:260
需要进行染色修复
# 
  • 图示第三种情况

image

代码

int main() {
        TreeNode *root_160 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_85 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_240 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_260 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_250 = (TreeNode *)malloc(sizeof(TreeNode));

        root_160->data = 160; root_160->color = BLACK;
        node_85->data = 85; node_85->color = BLACK;
        node_240->data = 240; node_240->color = BLACK;
        node_260->data = 260; node_260->color = RED;
        node_250->data = 250; node_250->color = RED;

        root_160->left = node_85;
        root_160->right = node_240;
        node_240->right = node_260;
        node_260->left = node_250;

        InsertFixup1(&root_160,node_250);
        return 0;
}

执行结果

# ./a.out 
插入数据:250
需要进行旋转修复
# 

3.2 核心代码

// 检测红黑树插入 是否需要修复
if ((parent->color == RED) && (uncleColor == RED)) {
    // 父亲节点为红色,叔叔节点为红色,需要进行染色修复
    printf("需要进行染色修复\n");

} else if((parent->color == RED) && uncleColor == BLACK) {
    // 父节点为红色,叔叔节点为黑色,则需要进行旋转
    printf("需要进行旋转修复\n");

} else {
    // 无需进行修复
    printf("无需进行修复\n");

}

3.3 具体函数实现

宏定义/结构体

# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>

# define RED 1
# define BLACK 0

typedef struct {
        int data; // 数据节点
        struct TreeNode *left; // 左子树
        struct TreeNode *right; // 右字树
        int color;  // 二叉树颜色,1: 红色 0:黑色

} TreeNode , *PTreeNode;

具体函数

PTreeNode InsertFixup1(PTreeNode *root,PTreeNode newNode) {

        printf("插入数据:%d\n",newNode->data);

        TreeNode *parent = NULL; // 父亲节点
        TreeNode *grandParent = NULL; // 爷爷节点 
        TreeNode *greatGrandParent = NULL; // 祖爷爷节点
        TreeNode *uncle = NULL; // 叔叔节点
        int uncleColor = 0; // 叔叔节点颜色,默认为黑色

        // 寻找节点 父亲/爷爷祖爷爷节点
        TreeNode *tmp = (*root);
        while (tmp != NULL) {
                if (newNode->data == tmp->data) {
                        break;
                }
                greatGrandParent = grandParent;
                grandParent = parent;
                parent = tmp;

                (newNode->data > tmp->data) ? (tmp = tmp->right) : (tmp = tmp->left);
        }

        // 当前节点是根节点,染成黑色
        if (newNode == (*root)) {
                printf("根节点,需要进行染色操作\n");
        }
    
    	// 只有2层就退出去
        if (grandParent == NULL) return;
    
        // 获取叔叔节点
        (parent == grandParent->left) ? (uncle = grandParent->right) : (uncle = grandParent->left);

        // 获取叔叔节点颜色
        if (uncle != NULL) uncleColor = uncle->color;

    	// 检测红黑树插入 是否需要修复
        if ((parent->color == RED) && (uncleColor == RED)) {
                // 父亲节点为红色,叔叔节点为红色,需要进行染色修复
                printf("需要进行染色修复\n");

        } else if((parent->color == RED) && uncleColor == BLACK) {
                // 父节点为红色,叔叔节点为黑色,则需要进行旋转
                printf("需要进行旋转修复\n");

        } else {
                // 无需进行修复
                printf("无需进行修复\n");
            
        }
}

4. 红黑树插入染色修复

染色修复

  1. 父亲节点叔叔节点 染成黑色
  2. 将爷爷节点染成红色
  3. 爷爷节点赋值给当前节点 ,再次判断是否需要染色处理。

4.1 图示

image

如上图所示,新插入节点为 260(当前节点) , 父亲节点为 240, 爷爷节点为 160, 叔叔节点为 85

4.2 染色处理

将 父亲节点 和 叔叔节点染成黑色,爷爷节点染成红色,然后将 当前节点 挪至 爷爷几点,再次判断是否需要染色处理。

image

如上图所示,将 父亲节点(240) 和 叔叔节点 (85) 染成黑色后, 将爷爷节点(160)染成红色后将当前节点 挪至爷爷节点(160为红色节点,且当前节点指向160),继续获取节点。

4.3 代码实现

核心代码

// 染色操作
if ((parent->color == RED) && (uncleColor == RED)) {
    parent->color = BLACK;
    uncle->color = BLACK;
    grandParent->color = RED;

    newNode = grandParent;
    continue;
}

染色完整代码

宏定义/结构体

# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>

# define RED 1
# define BLACK 0

typedef struct {
        int data; // 数据节点
        struct TreeNode *left; // 左子树
        struct TreeNode *right; // 右字树
        int color;  // 二叉树颜色,1: 红色 0:黑色

} TreeNode , *PTreeNode;

插入函数

PTreeNode InsertFixup1(PTreeNode *root,PTreeNode newNode) {

        printf("插入数据:%d\n",newNode->data);

        TreeNode *parent = NULL; // 父亲节点
        TreeNode *grandParent = NULL; // 爷爷节点 
        TreeNode *greatGrandParent = NULL; // 祖爷爷节点
        TreeNode *uncle = NULL; // 叔叔节点
        int uncleColor = BLACK; // 叔叔节点颜色,默认为黑色

        while (true) {

                parent = grandParent = greatGrandParent = uncle = NULL;
                uncleColor = BLACK;

                // 寻找节点 父亲/爷爷祖爷爷节点
                TreeNode *tmp = (*root);
                while (tmp != NULL) {
                        if (newNode->data == tmp->data) {
                                break;
                        }
                        greatGrandParent = grandParent;
                        grandParent = parent;
                        parent = tmp;

                        (newNode->data > tmp->data) ? (tmp = tmp->right) : (tmp = tmp->left);
                }

                // 当前节点是根节点,染成黑色
                if (newNode == (*root)) {
                        printf("根节点,需要进行染色操作\n");
                }

                if (grandParent == NULL) return;

                // 获取叔叔节点
                (parent == grandParent->left) ? (uncle = grandParent->right) : (uncle = grandParent->left);

                // 获取叔叔节点颜色
                if (uncle != NULL) uncleColor = uncle->color;



                if ((parent->color == RED) && (uncleColor == RED)) {
                        // 父亲节点为红色,叔叔节点为红色,需要进行染色修复
                        printf("需要进行染色修复\n");

                        parent->color = BLACK;
                        uncle->color = BLACK;
                        grandParent->color = RED;

                        newNode = grandParent;
                        continue;

                } else if((parent->color == RED) && uncleColor == BLACK) {
                        // 父节点为红色,叔叔节点为黑色,则需要进行旋转
                        printf("需要进行旋转修复\n");
                        break;


                } else {
                        // 无需进行修复
                        printf("无需进行修复\n");
                        break;

                }
        }

}

主函数/遍历函数

// 前序遍历
void Print1(TreeNode *root) {
        if (NULL == root) return;
        printf("[颜色:%s  数据:%d]\t",(root->color == RED) ? ("红"):("黑") ,root->data);
        Print1(root->left);
        Print1(root->right);
}

int main() {
        TreeNode *root_160 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_85 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_240 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_260 = (TreeNode *)malloc(sizeof(TreeNode));
        TreeNode *node_250 = (TreeNode *)malloc(sizeof(TreeNode));

        root_160->data = 160; root_160->color = BLACK;
        node_85->data = 85; node_85->color = 1;
        node_240->data = 240; node_240->color = 1;
        node_260->data = 260; node_260->color = RED;

        root_160->left = node_85;
        root_160->right = node_240;
        node_240->right = node_260;

        InsertFixup1(&root_160,node_260);
        Print1(root_160);
        printf("\n");
        return 0;
}

执行结果

# ./a.out 
插入数据:260
需要进行染色修复
根节点,需要进行染色操作
[颜色:红  数据:160]     [颜色:黑  数据:85]      [颜色:黑  数据:240]     [颜色:红  数据:260]
# 

5. 红黑树插入旋转修复

旋转修复

父亲节点为红色,叔叔节点为黑色,则需要进行旋转修复

而旋转修复又分为四种情况: 左左/左右/右左/右右

5.1 图示

黄色节点为 新插入节点 ,重点关注蓝色框框的树

左左情况

image

左右情况

image

右左情况

image

右右情况

image

5.2 判断方向

若新插入节点的父亲节点在爷爷节点的左边,且新插入节点在父亲节点的左边,则为 左左情况

若新插入节点的父亲节点在爷爷节点的左边,且新插入节点在父亲节点的右边,则为 左右情况

若新插入节点的父亲节点在爷爷节点的右边,且新插入节点在父亲节点的左边,则为 右左情况

若新插入节点的父亲节点在爷爷节点的右边,且新插入节点在父亲节点的右边,则为 右右情况

代码实现

if ((parent->color == RED) && uncleColor == BLACK) {
	if ((parent == grandParent->left) && (newNode == parent->left)) {
        // 左左情况
        
    } else if ((parent == grandParent->left) && (newNode == parent->right)) {
        // 左右情况
        
    } else if ((parent == grandParent->right) && (newNode == parent->left)) {
        // 右左情况
        
    } else if ((parent == grandParent->right) && (newNode == parent->right)) {
        // 右右情况
    }
}

5.3 旋转图示

左左情况

image

进行右旋操作

image

染色操作

将父亲节点(80)染成黑色,爷爷节点(85)染成红色, 当前节点(60)染成红色

image

左右情况

image

先进行左旋,将会变为【左左】情况一致

image

右左情况

image

先进行右旋,将会变为【右右】情况一致

image

上图变得和 即将讲述的 【右右】情况类似了

右右情况

image

进行左旋操作

image

进行染色处理

将父亲节点(90)染成黑色,将爷爷节点(85)染成红色,当前节点(100)染成红色

image

5.4 旋转代码实现

左左旋转

// 左左
if ((parent == grandParent->left) && (newNode == parent->left)) {
    grandParent->left = NULL;

    TreeNode *oldParentRight = parent->right;

    parent->right = grandParent;
    grandParent->left = oldParentRight;

    if ((*root) == grandParent) {
        (*root) = parent;
    } else {
        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
    }

    // 染色
    newNode->color = RED;
    grandParent->color = RED;
    parent->color = BLACK;
    //continue;
    break;
}

左右旋转

// 左右
if ((parent == grandParent->left) && (newNode == parent->right)) {
    grandParent->left = newNode;

    TreeNode *newNodeLeft = newNode->left;


    newNode->left = parent;
    parent->right = newNodeLeft;

    TreeNode *newNodeRight = newNode->right;
    newNode->right = grandParent;
    grandParent->left = newNodeRight;
    //newNode->left = parent;

    // 若要旋转的树是根节点
    if ((*root) == grandParent) {
        (*root) = newNode;
    } else {
        // 要旋转的树非根节点
        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
    }

    parent->color = RED;
    grandParent->color = RED;
    newNode->color = BLACK;
    //continue;
    break;
} 

右左旋转

// 右左
if ((parent == grandParent->right) && (newNode == parent->left)) {
    parent->left = NULL;

    TreeNode *newNodeRight = newNode->right;
    newNode->right = parent;
    parent->left = newNodeRight;

    grandParent->right = newNode;

    TreeNode *newNodeLeft = newNode->left;
    newNode->left = grandParent;
    grandParent->right = newNodeLeft;


    // 要旋转的树是根节点
    if ((*root) == grandParent) {
        (*root) = newNode;

    } else {
        // 要旋转的树是非根节点
        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
    }

    // 染色
    newNode->color = BLACK;
    grandParent->color = RED;
    parent->color = RED;
    //continue;
    break;
}

右右旋转

if ((parent == grandParent->right) && (newNode == parent->right)) {
    grandParent->right = NULL;

    TreeNode *oldParentLeft = parent->left;
    parent->left = grandParent;
    grandParent->right = oldParentLeft;

    // 要旋转的树是根节点
    if ((*root) == grandParent) {
        (*root) = parent;

    } else {
        // 要旋转的树是非根节点
        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
    }

    // 染色
    grandParent->color = RED;
    newNode->color = RED;
    parent->color = BLACK;
    //continue;
    break;
}

整合代码插入修复函数

PTreeNode InsertFixup(PTreeNode *root,PTreeNode newNode) {

        TreeNode *parent = NULL; // 父亲节点
        TreeNode *grandParent = NULL; // 爷爷节点 
        TreeNode *greatGrandParent = NULL; // 祖爷爷节点
        TreeNode *uncle = NULL; // 叔叔节点
        int uncleColor = BLACK; // 叔叔节点颜色,默认为黑色

        while (true) {

                parent = grandParent = greatGrandParent = uncle = NULL;
                uncleColor = BLACK;

                // 寻找节点 父亲/爷爷祖爷爷节点
                TreeNode *tmp = (*root);
                while (tmp != NULL) {
                        if (newNode->data == tmp->data) {
                                break;
                        }
                        greatGrandParent = grandParent;
                        grandParent = parent;
                        parent = tmp;

                        (newNode->data > tmp->data) ? (tmp = tmp->right) : (tmp = tmp->left);
                }

                // 当前节点是根节点,染成黑色
                if (newNode == (*root)) {
                        printf("根节点,需要进行染色操作\n");
                        (*root)->color = BLACK;
                }

                if (grandParent == NULL) return;

                // 获取叔叔节点
                (parent == grandParent->left) ? (uncle = grandParent->right) : (uncle = grandParent->left);

                // 获取叔叔节点颜色
                if (uncle != NULL) uncleColor = uncle->color;



                if ((parent->color == RED) && (uncleColor == RED)) {
                        // 父亲节点为红色,叔叔节点为红色,需要进行染色修复
                        printf("需要进行染色修复\n");

                        parent->color = BLACK;
                        uncle->color = BLACK;
                        grandParent->color = RED;

                        newNode = grandParent;
                        continue;

                } else if((parent->color == RED) && uncleColor == BLACK) {
                        // 父节点为红色,叔叔节点为黑色,则需要进行旋转
                        printf("需要进行旋转修复\n");
                        // 左左
                        if ((parent == grandParent->left) && (newNode == parent->left)) {
                                grandParent->left = NULL;

                                TreeNode *oldParentRight = parent->right;

                                parent->right = grandParent;
                                grandParent->left = oldParentRight;

                                if ((*root) == grandParent) {
                                        (*root) = parent;
                                } else {
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
                                }

                                // 染色
                                newNode->color = RED;
                                grandParent->color = RED;
                                parent->color = BLACK;
                                //continue;
                                break;
                        // 左右
                        } else if ((parent == grandParent->left) && (newNode == parent->right)) {
                                grandParent->left = newNode;

                                TreeNode *newNodeLeft = newNode->left;


                                newNode->left = parent;
                                parent->right = newNodeLeft;

                                TreeNode *newNodeRight = newNode->right;
                                newNode->right = grandParent;
                                grandParent->left = newNodeRight;
                                newNode->left = parent;

                                // 若要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = newNode;
                                } else {
                                        // 要旋转的树非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
                                }

                                parent->color = RED;
                                grandParent->color = RED;
                                newNode->color = BLACK;
                                //continue;
                                break;

                        // 右左
                        } else if ((parent == grandParent->right) && (newNode == parent->left)) {
                                parent->left = NULL;

                                TreeNode *newNodeRight = newNode->right;
                                newNode->right = parent;
                                parent->left = newNodeRight;

                                grandParent->right = newNode;

                                TreeNode *newNodeLeft = newNode->left;
                                newNode->left = grandParent;
                                grandParent->right = newNodeLeft;


                                // 要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = newNode;

                                } else {
                                        // 要旋转的树是非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
                                }

                                // 染色
                                newNode->color = BLACK;
                                grandParent->color = RED;
                                parent->color = RED;
                                //continue;
                                break;

                        // 右右
                        } else if ((parent == grandParent->right) && (newNode == parent->right)) {
                                grandParent->right = NULL;

                                TreeNode *oldParentLeft = parent->left;
                                parent->left = grandParent;
                                grandParent->right = oldParentLeft;

                                // 要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = parent;

                                } else {
                                        // 要旋转的树是非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
                                }

                                // 染色
                                grandParent->color = RED;
                                newNode->color = RED;
                                parent->color = BLACK;
                                //continue;
                                break;
                        }
                } else {
                        // 无需进行修复
                        printf("无需进行修复\n");
                        break;
                }
        }
        return (*root);
}

6. 插入全部代码

引入 搜索二叉树 插入代码

# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>

# define RED 1
# define BLACK 0

typedef struct {
        int data; // 数据节点
        struct TreeNode *left; // 左子树
        struct TreeNode *right; // 右字树
        int color;  // 二叉树颜色,1: 红色 0:黑色

} TreeNode , *PTreeNode;

PTreeNode InsertFixup(PTreeNode *root,PTreeNode newNode) {

        TreeNode *parent = NULL; // 父亲节点
        TreeNode *grandParent = NULL; // 爷爷节点 
        TreeNode *greatGrandParent = NULL; // 祖爷爷节点
        TreeNode *uncle = NULL; // 叔叔节点
        int uncleColor = BLACK; // 叔叔节点颜色,默认为黑色

        while (true) {

                parent = grandParent = greatGrandParent = uncle = NULL;
                uncleColor = BLACK;

                // 寻找节点 父亲/爷爷祖爷爷节点
                TreeNode *tmp = (*root);
                while (tmp != NULL) {
                        if (newNode->data == tmp->data) {
                                break;
                        }
                        greatGrandParent = grandParent;
                        grandParent = parent;
                        parent = tmp;

                        (newNode->data > tmp->data) ? (tmp = tmp->right) : (tmp = tmp->left);
                }

                // 当前节点是根节点,染成黑色
                if (newNode == (*root)) {
                        printf("根节点,需要进行染色操作\n");
                        (*root)->color = BLACK;
                }

                if (grandParent == NULL) return;

                // 获取叔叔节点
                (parent == grandParent->left) ? (uncle = grandParent->right) : (uncle = grandParent->left);

                // 获取叔叔节点颜色
                if (uncle != NULL) uncleColor = uncle->color;



                if ((parent->color == RED) && (uncleColor == RED)) {
                        // 父亲节点为红色,叔叔节点为红色,需要进行染色修复
                        printf("需要进行染色修复\n");

                        parent->color = BLACK;
                        uncle->color = BLACK;
                        grandParent->color = RED;

                        newNode = grandParent;
                        continue;

                } else if((parent->color == RED) && uncleColor == BLACK) {
                        // 父节点为红色,叔叔节点为黑色,则需要进行旋转
                        printf("需要进行旋转修复\n");
                        // 左左
                        if ((parent == grandParent->left) && (newNode == parent->left)) {
                                grandParent->left = NULL;

                                TreeNode *oldParentRight = parent->right;

                                parent->right = grandParent;
                                grandParent->left = oldParentRight;

                                if ((*root) == grandParent) {
                                        (*root) = parent;
                                } else {
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
                                }

                                // 染色
                                newNode->color = RED;
                                grandParent->color = RED;
                                parent->color = BLACK;
                                //continue;
                                break;
                        // 左右
                        } else if ((parent == grandParent->left) && (newNode == parent->right)) {
                                grandParent->left = newNode;

                                TreeNode *newNodeLeft = newNode->left;


                                newNode->left = parent;
                                parent->right = newNodeLeft;

                                TreeNode *newNodeRight = newNode->right;
                                newNode->right = grandParent;
                                grandParent->left = newNodeRight;
                                newNode->left = parent;

                                // 若要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = newNode;
                                } else {
                                        // 要旋转的树非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
                                }

                                parent->color = RED;
                                grandParent->color = RED;
                                newNode->color = BLACK;
                                //continue;
                                break;

                        // 右左
                        } else if ((parent == grandParent->right) && (newNode == parent->left)) {
                                parent->left = NULL;

                                TreeNode *newNodeRight = newNode->right;
                                newNode->right = parent;
                                parent->left = newNodeRight;

                                grandParent->right = newNode;

                                TreeNode *newNodeLeft = newNode->left;
                                newNode->left = grandParent;
                                grandParent->right = newNodeLeft;


                                // 要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = newNode;

                                } else {
                                        // 要旋转的树是非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = newNode) : (greatGrandParent->right = newNode);
                                }

                                // 染色
                                newNode->color = BLACK;
                                grandParent->color = RED;
                                parent->color = RED;
                                //continue;
                                break;

                        // 右右
                        } else if ((parent == grandParent->right) && (newNode == parent->right)) {
                                grandParent->right = NULL;

                                TreeNode *oldParentLeft = parent->left;
                                parent->left = grandParent;
                                grandParent->right = oldParentLeft;

                                // 要旋转的树是根节点
                                if ((*root) == grandParent) {
                                        (*root) = parent;

                                } else {
                                        // 要旋转的树是非根节点
                                        (greatGrandParent->left == grandParent) ? (greatGrandParent->left = parent) : (greatGrandParent->right = parent);
                                }

                                // 染色
                                grandParent->color = RED;
                                newNode->color = RED;
                                parent->color = BLACK;
                                //continue;
                                break;
                        }
                } else {
                        // 无需进行修复
                        printf("无需进行修复\n");
                        break;
                }
        }
        return (*root);
}

PTreeNode Insert(PTreeNode *root,int data) {

        printf("插入数据: %d\n",data);
        TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
        newNode->data = data;
        newNode->color = RED; // 新增节点染成红色

        TreeNode *parent = NULL;
        TreeNode *grandParent = NULL;

        if (NULL == (*root)) {
                //printf("插入根节点\n");
                newNode->color = BLACK; // 将头结点染成黑色
                return newNode;
        } else {
                TreeNode *tmp = (*root);
                while (tmp != NULL) {
                        //printf("插入查找值: %d\n",tmp->data);
                        grandParent = parent;
                        parent = tmp;

                        if (data > tmp->data){
                                tmp = tmp->right;
                        } else if (data < tmp->data){
                                tmp = tmp->left;
                        } else {
                                printf("%d 该值已经存在\n",data);
                        }
                }
                if (data > parent->data) {
                        parent->right = newNode;
                        //printf("parent data:%d newNode data:%d\n",parent->data,newNode->data);
                } else {
                        parent->left = newNode;
                }
        }
        // 如果插入父节点是黑色,则保持不变
        if (parent->color == BLACK) return (*root);

        // 进行插入修复
        return InsertFixup(root,newNode); 
}


// 中序遍历
void Print2(TreeNode *root) {
        if (NULL == root) return;
        Print2(root->left);
        printf("[颜色:%s  数据:%d]\t",(root->color == RED) ? ("红"):("黑") ,root->data);
        Print2(root->right);
}
// 前序遍历
void Print1(TreeNode *root) {
        if (NULL == root) return;
        printf("[颜色:%s  数据:%d]\t",(root->color == RED) ? ("红"):("黑") ,root->data);
        Print1(root->left);
        Print1(root->right);
}

int main() {
        TreeNode *root = NULL;

        int num[] = {10,6,11,4,8,20,19,26,17,23,35,40,55,32,231};

        int i;
        for (i=0;i<sizeof(num)/sizeof(int);i++) {
                root = Insert(&root,num[i]);
        }

        printf("\n");
        Print1(root);
        printf("\n");

        return 0;
}

执行结果

# gcc RedBlackTreeInsert.c -w -g
# ./a.out 
插入数据: 10
插入数据: 6
插入数据: 11
插入数据: 4
需要进行染色修复
根节点,需要进行染色操作
插入数据: 8
插入数据: 20
插入数据: 19
需要进行旋转修复
插入数据: 26
需要进行染色修复
插入数据: 17
插入数据: 23
需要进行旋转修复
插入数据: 35
需要进行染色修复
需要进行旋转修复
插入数据: 40
需要进行旋转修复
插入数据: 55
需要进行染色修复
需要进行染色修复
根节点,需要进行染色操作
插入数据: 32
插入数据: 231
需要进行旋转修复

[颜色:黑  数据:19]      [颜色:黑  数据:10]      [颜色:黑  数据:6]       [颜色:红  数据:4]       [颜色:红  数据:8]       [颜色:黑  数据:11]  [颜色:红  数据:17]      [颜色:黑  数据:23]      [颜色:黑  数据:20]      [颜色:红  数据:35]      [颜色:黑  数据:26]      [颜色:红  数据:32] [颜色:黑  数据:55]      [颜色:红  数据:40]      [颜色:红  数据:231]
# 
posted @ 2021-10-22 23:57  pdudos  阅读(278)  评论(0编辑  收藏  举报