C语言 红黑树

红黑树简介

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。

红黑树的模拟过程可以看链接:InsertSortion

红黑树有五个性质:

性质1. 节点是红色或黑色。
性质2. 根节点是黑色
性质3. 每个叶节点(NIL节点,空节点)是黑色的。
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

实现过程

什么情况下会破坏红黑树呢?参照链接:红黑树(一)之 原理和算法详细介绍
除了根节点,插入的节点都是红色的。
总结一下就是出现以下几种情况:
这里写图片描述

对于前四种情况,我们通过左旋右旋操作去解决。(注:关于什么是左旋和右旋可以参照链接C语言 AVL树

最后一种情况,操作则不一样:
这里写图片描述
所以对于红黑树的插入从操作上来看则只是比AVL树多了最后一种情况。

代码实现

节点

typedef struct Bi{
    int val;
    int pos;

    int color;
    struct Bi *parent;
    struct Bi *left_child;
    struct Bi *right_child;
} Btree, *BtreePtr;

ADT:

#define COLOR(p)     ( (p==NULL) ? BLACK : (((BtreePtr)(p))->color) )
#define REB 1
#define BLACK 2

BtreePtr rightRotateRB(BtreePtr a) ;
BtreePtr leftRotateRB(BtreePtr a);
BtreePtr rightLeftRotateRB(BtreePtr a);
BtreePtr leftRightRotateRB(BtreePtr a);

BtreePtr _checkColor(BtreePtr p); //检查节点之后两层节点是否出现失衡,并让树平衡
BtreePtr _insertRBTree(BtreePtr p, const int key, const int pos);

BtreePtr insertRBTree(BtreePtr root, const int key, const int pos);

完整代码

#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#define COLOR(p)     ( (p==NULL) ? BLACK : (((BtreePtr)(p))->color) )
#define REB 1
#define BLACK 2

typedef struct Bi{
    int val;
    int pos;
    int color;

    struct Bi *parent;
    struct Bi *left_child;
    struct Bi *right_child;
} Btree, *BtreePtr;

int midSearch(const BtreePtr a, const int key) {
    if (a != NULL) {
        if (key > a->val) {
            return midSearch(a->right_child, key);
        }
        else if(key < a->val) {
            return midSearch(a->left_child, key);
        }
        else {
            return a->pos;
        }
    }
    else {
        return -1;
    }
}

void freeTree(BtreePtr b) {
    if (b->right_child !=NULL) {
        freeTree(b->right_child);
    }
    if (b->left_child != NULL) {
        freeTree(b->left_child);
    }
}

BtreePtr leftRotateRB(BtreePtr p) {
    BtreePtr b = (BtreePtr)malloc(sizeof(Btree));
    b = p->right_child;
    p->right_child = b->left_child;
    p->color = REB;

    b->color = BLACK;
    b->left_child = p;
    b->parent = p->parent;
    b->left_child->parent = b;
    return b;
}

BtreePtr rightRotateRB(BtreePtr p) {
    BtreePtr b = (BtreePtr)malloc(sizeof(Btree));
    b = p->left_child;
    p->left_child = b->right_child;
    p->color = REB;

    b->color = BLACK;
    b->right_child = p;
    b->parent = p->parent;
    b->right_child->parent = b;
    return b;
}

BtreePtr rightleftRotateRB(BtreePtr p) {
    p->right_child = rightRotateRB(p->right_child);
    p = leftRotateRB(p);
    return p;
}

BtreePtr leftrightRotateRB(BtreePtr p) {
    p->right_child = leftRotateRB(p->right_child);
    p = rightRotateRB(p);
    return p;
}

BtreePtr _checkColor(BtreePtr p) {
    int p_color = COLOR(p);

    int right = COLOR(p->right_child);
    int left = COLOR(p->left_child);

    if (right == REB && left == BLACK) {
        int right_left = COLOR(p->right_child->left_child);
        int right_right = COLOR(p->right_child->right_child);

        if (right_right == REB) {
            p = leftRotateRB(p);
        }
        else if (right_left == REB) {
            p = rightleftRotateRB(p);
        }
    }

    else if (left == REB  && right == BLACK) {
        int left_right = COLOR(p->left_child->right_child);
        int left_left = COLOR(p->left_child->left_child);

        if (left_left == REB) {
            p = rightRotateRB(p);
        }
        else if (left_right == REB) {
            p = leftrightRotateRB(p);
        }
    }

    else if (right == REB && left == REB) {
        int left_right = COLOR(p->left_child->right_child);
        int left_left = COLOR(p->left_child->left_child);
        int right_left = COLOR(p->right_child->left_child);
        int right_right = COLOR(p->right_child->right_child);

        if (left_right == REB || left_left == REB || right_left == REB || right_right == REB) {
            if (p->parent != NULL) {
                p->color = REB;
            }
            p->left_child->color = BLACK;
            p->right_child->color = BLACK;
        }
    }
    return p;
}

BtreePtr _insertRBTree(BtreePtr p, const int key, const int pos) {
    if (p == NULL) {
        BtreePtr b = (BtreePtr)malloc(sizeof(Btree));
        if (b != NULL) {
            memset(b, 0, sizeof(Btree));
            b->val = key;
            b->pos = pos;
            b->color = REB;
            p = b;
        }
        else {
            return NULL;
        }
    }
    else
    {
        if (key < p->val) {
            p->left_child = _insertRBTree(p->left_child, key, pos);
            p->left_child->parent = p;
        }
        else {
            p->right_child = _insertRBTree(p->right_child, key, pos);
            p->right_child->parent = p;
        }
    }
    p = _checkColor(p);
    return p;
}

BtreePtr insertRBTree(BtreePtr root, const int key, const int pos) {
    if (root == NULL) {
        BtreePtr p = (BtreePtr)malloc(sizeof(Btree));
        if (p != NULL) {
            memset(p, 0, sizeof(Btree));
            p->val = key;
            p->pos = pos;
            p->color = BLACK;
            root = p;
        }
        else {
            puts("内存不足");
        }
    }
    else
    {
        root = _insertRBTree(root, key, pos);
    }
    return root;
}


int RBTreeSearch(const int *a, const int length, const int key) {
    BtreePtr root = NULL;
    for (int i = 0; i < length; i++) {
        root = insertRBTree(root, a[i], i);  //构建二叉树
    }
    int pos = midSearch(root, key);
    freeTree(root); //不能直接使用free(b)
    return pos;
}



void main() {
    const int length = 6;
    int my_array[6] = { 5, 7, 9,11 ,8,10};
    printf("%d \n", RBTreeSearch(my_array, length, 7));
}
### C语言实现红黑树数据结构 #### 节点与树的定义 在C语言中,红黑树的数据结构可以通过定义节点和树两种结构体来完成。以下是具体的代码示例: ```c #include <stdio.h> #include <stdlib.h> typedef enum { RED, BLACK } NodeColor; // 定义红黑树节点结构 typedef struct RBTreeNode { int data; NodeColor color; struct RBTreeNode *left, *right, *parent; } RBTreeNode; // 定义红黑树本身 typedef struct RBTree { RBTreeNode *root; RBTreeNode *nil; // NIL节点用于简化边界条件处理 } RBTree; ``` 以上代码片段定义了红黑树的基本结构[^1]。 --- #### 辅助函数 为了支持红黑树的操作,通常需要一些辅助函数,比如左旋、右旋以及颜色调整等。这些操作对于维持红黑树的性质至关重要。 ##### 左旋操作 当某个子树不平衡时,可以执行左旋操作将其恢复平衡。 ```c void leftRotate(RBTree *T, RBTreeNode *x) { RBTreeNode *y = x->right; // 设置 y x->right = y->left; // 将 y 的左子树转为 x 的右子树 if (y->left != T->nil) // 如果 y 的左子树不是 nil,则更新其父指针 y->left->parent = x; y->parent = x->parent; // 更新 y 的父指针 if (x->parent == T->nil) // 如果 x 是根节点 T->root = y; else if (x == x->parent->left)// 如果 x 是左孩子 x->parent->left = y; else // 否则 x 是右孩子 x->parent->right = y; y->left = x; // 把 x 放到 y 的左边 x->parent = y; // 更新 x 的父指针 } ``` ##### 右旋操作 类似于左旋,右旋也可以用来恢复树的平衡。 ```c void rightRotate(RBTree *T, RBTreeNode *y) { RBTreeNode *x = y->left; // 设置 x y->left = x->right; // 将 x 的右子树转为 y 的左子树 if (x->right != T->nil) // 如果 x 的右子树不是 nil,则更新其父指针 x->right->parent = y; x->parent = y->parent; // 更新 x 的父指针 if (y->parent == T->nil) // 如果 y 是根节点 T->root = x; else if (y == y->parent->right) // 如果 y 是右孩子 y->parent->right = x; else // 否则 y 是左孩子 y->parent->left = x; x->right = y; // 把 y 放到 x 的右边 y->parent = x; // 更新 y 的父指针 } ``` 上述两段代码分别实现了左旋和右旋的功能。 --- #### 插入操作 插入新节点后可能破坏红黑树的性质,因此需要通过一系列修复操作使其重新满足红黑树的要求。 ```c void rbInsertFixup(RBTree *T, RBTreeNode *z) { while (z->parent->color == RED) { // 当 z 的父节点是红色时 if (z->parent == z->parent->parent->left) { // 若 z 的父节点是祖父节点的左孩子 RBTreeNode *y = z->parent->parent->right; // 获取叔叔节点 if (y->color == RED) { // Case 1: 叔叔节点也是红色 z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { // Case 2 和 Case 3: 叔叔节点是黑色 if (z == z->parent->right) { // Case 2: z 是右孩子 z = z->parent; leftRotate(T, z); // 执行左旋转换为 Case 3 } z->parent->color = BLACK; // Case 3: z 是左孩子 z->parent->parent->color = RED; rightRotate(T, z->parent->parent); } } else { // 对称情况:如果 z 的父节点是祖父节点的右孩子 RBTreeNode *y = z->parent->parent->left; if (y->color == RED) { z->parent->color = BLACK; y->color = BLACK; z->parent->parent->color = RED; z = z->parent->parent; } else { if (z == z->parent->left) { z = z->parent; rightRotate(T, z); } z->parent->color = BLACK; z->parent->parent->color = RED; leftRotate(T, z->parent->parent); } } } T->root->color = BLACK; // 确保根节点始终为黑色 } RBTreeNode* createNode(int key, RBTreeNode *parent, RBTreeNode *nil) { RBTreeNode *node = malloc(sizeof(RBTreeNode)); node->data = key; node->color = RED; node->left = nil; node->right = nil; node->parent = parent; return node; } void rbInsert(RBTree *T, int key) { RBTreeNode *z = createNode(key, NULL, T->nil); RBTreeNode *y = T->nil; RBTreeNode *x = T->root; while (x != T->nil) { // 查找合适的位置插入新节点 y = x; if (z->data < x->data) x = x->left; else x = x->right; } z->parent = y; // 链接父子关系 if (y == T->nil) // 新节点成为根节点的情况 T->root = z; else if (z->data < y->data) y->left = z; else y->right = z; z->left = T->nil; // 初始化新节点的孩子为 nil z->right = T->nil; z->color = RED; // 初始设置为红色 rbInsertFixup(T, z); // 修正红黑树性质 } ``` 此部分代码完成了红黑树的插入逻辑及其后续修复过程[^4]。 --- #### 删除操作 删除操作相对复杂,涉及多种场景下的结构调整。测试过程中需特别注意各种特殊情况的覆盖[^2]。 --- #### 主程序示例 以下是一个简单的主程序演示如何初始化并填充一棵红黑树。 ```c int main() { RBTree tree; tree.root = NULL; tree.nil = malloc(sizeof(RBTreeNode)); // 创建一个哨兵节点作为 nil tree.nil->color = BLACK; tree.nil->left = tree.nil->right = tree.nil->parent = NULL; int arr[] = {7, 3, 18, 10, 22, 8, 11, 26, 2, 6, 13}; int n = sizeof(arr) / sizeof(arr[0]); for (int i = 0; i < n; i++) rbInsert(&tree, arr[i]); printf("Red-Black Tree created successfully.\n"); return 0; } ``` 这段代码展示了如何构建一颗基本的红黑树实例[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值