数据结构---红黑树

红黑树(Red - Black Tree)

1.定义

红黑树是一种自平衡的二叉查找树,它在每一个节点上增加另一个存储位来表示节点的颜色,可以是红色或者黑色。通过这些颜色的约束,红黑树能够保证从根到叶子节点的最长路径不会超过最短路径的两倍,从而保持大致的平衡。

2.性质

1.节点是红色或者黑色。

2.根节点是黑色。

3.叶子节点(空节点)是黑色。

4.如果一个节点是红色,则它的两个子节点都是黑色。(不能有两个连续的红色节点)

5.从任意节点到其每个叶子的所有路径都包含相同数量的黑色节点。

以下是红黑树的简单实现代码(仅包含插入操作):

#include <iostream>
#include<vector>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

// 定义节点颜色
typedef enum { RED, BLACK } Color;

// 定义红黑树节点
typedef struct RBTreeNode {
    int key;
    Color color;
    struct RBTreeNode* left;
    struct RBTreeNode* right;
    struct RBTreeNode* parent;
} RBTreeNode;

// 创建新节点
RBTreeNode* createNode(int key) {
    RBTreeNode* newNode = (RBTreeNode*)malloc(sizeof(RBTreeNode));
    newNode->key = key;
    newNode->color = RED; // 新节点默认为红色
    newNode->left = NULL;
    newNode->right = NULL;
    newNode->parent = NULL;
    return newNode;
}

// 左旋操作
void leftRotate(RBTreeNode** root, RBTreeNode* x) {
    RBTreeNode* y = x->right; // 设置y
    x->right = y->left; // 转移y的左子树到x的右子树
    if (y->left != NULL) {
        y->left->parent = x;
    }
    y->parent = x->parent; // 链接x的父节点到y
    if (x->parent == NULL) {
        *root = y;
    }
    else if (x == x->parent->left) {
        x->parent->left = y;
    }
    else {
        x->parent->right = y;
    }
    y->left = x; // 把x放到y的左子树
    x->parent = y;
}

// 右旋操作
void rightRotate(RBTreeNode** root, RBTreeNode* y) {
    RBTreeNode* x = y->left; // 设置x
    y->left = x->right; // 转移x的右子树到y的左子树
    if (x->right != NULL) {
        x->right->parent = y;
    }
    x->parent = y->parent; // 链接y的父节点到x
    if (y->parent == NULL) {
        *root = x;
    }
    else if (y == y->parent->right) {
        y->parent->right = x;
    }
    else {
        y->parent->left = x;
    }
    x->right = y; // 把y放到x的右子树
    y->parent = x;
}

// 修复插入操作后的红黑树性质
void fixInsert(RBTreeNode** root, RBTreeNode* newNode) {
    RBTreeNode* uncle;

    while (newNode != *root && newNode->parent->color == RED) {
        if (newNode->parent == newNode->parent->parent->left) {
            uncle = newNode->parent->parent->right; // 叔叔节点
            if (uncle != NULL && uncle->color == RED) {
                // 情况1:叔叔是红色
                newNode->parent->color = BLACK;
                uncle->color = BLACK;
                newNode->parent->parent->color = RED;
                newNode = newNode->parent->parent;
            }
            else {
                if (newNode == newNode->parent->right) {
                    // 情况2:叔叔是黑色,且新节点是右孩子
                    newNode = newNode->parent;
                    leftRotate(root, newNode);
                }
                // 情况3:叔叔是黑色,且新节点是左孩子
                newNode->parent->color = BLACK;
                newNode->parent->parent->color = RED;
                rightRotate(root, newNode->parent->parent);
            }
        }
        else {
            uncle = newNode->parent->parent->left; // 叔叔节点
            if (uncle != NULL && uncle->color == RED) {
                // 情况1:叔叔是红色
                newNode->parent->color = BLACK;
                uncle->color = BLACK;
                newNode->parent->parent->color = RED;
                newNode = newNode->parent->parent;
            }
            else {
                if (newNode == newNode->parent->left) {
                    // 情况2:叔叔是黑色,且新节点是左孩子
                    newNode = newNode->parent;
                    rightRotate(root, newNode);
                }
                // 情况3:叔叔是黑色,且新节点是右孩子
                newNode->parent->color = BLACK;
                newNode->parent->parent->color = RED;
                leftRotate(root, newNode->parent->parent);
            }
        }
    }
    (*root)->color = BLACK; // 根节点必须是黑色
}

// 插入新节点
void insert(RBTreeNode** root, int key) {
    RBTreeNode* newNode = createNode(key);
    RBTreeNode* current = *root;
    RBTreeNode* parent = NULL;

    // 查找插入位置
    while (current != NULL) {
        parent = current;
        if (newNode->key < current->key) {
            current = current->left;
        }
        else {
            current = current->right;
        }
    }
    newNode->parent = parent; // 设置父节点

    if (parent == NULL) {
        *root = newNode; // 如果树为空,新节点成为根节点
    }
    else if (newNode->key < parent->key) {
        parent->left = newNode; // 插入到父节点的左子树
    }
    else {
        parent->right = newNode; // 插入到父节点的右子树
    }

    fixInsert(root, newNode); // 修复红黑树性质
}

// 打印红黑树(中序遍历)
void inorderTraversal(RBTreeNode* root) 
{
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d(%s) ", root->key, root->color == RED ? "RED" : "BLACK");
        inorderTraversal(root->right);
    }
}

int main() 
{
    RBTreeNode* root = NULL;

    insert(&root, 10);
    insert(&root, 20);
    insert(&root, 30);
    insert(&root, 40);
    insert(&root, 50);

    printf("Inorder traversal of the constructed Red - Black Tree is:\n");
    inorderTraversal(root);
    printf("\n");

    return 0;
}

代码运行结果:

微信截图_20250608122112

说明:以上代码来自于Kimi AI助手。

好文链接:

数据结构(8)-- 图解红黑树

【高阶数据结构】红黑树详解

### Java 中红黑树数据结构实现与应用 #### 红黑树简介 红黑树是一种自平衡二叉查找树,在计算机科学中用于高效地存储和检索键值对。该数据结构的特点在于其能够自动调整节点位置来维持一定的平衡条件,从而保证最坏情况下的时间复杂度为 O(log n)[^1]。 #### 平衡特性对比 相较于 AVL 树而言,尽管两者都致力于维护二叉查找树的高度接近于最小可能高度,但是由于红黑树对于旋转次数的要求较低,因此在频繁发生插入或删除的情况下表现更优;而像 `TreeMap` 和 `TreeSet` 这样的集合类正是利用这一点实现了高效的增删改查功能[^2]。 #### 关键属性定义 为了满足上述提到的性质,每棵红黑树中的结点除了拥有指向左右子树以及父辈指针外还需要额外记录颜色信息(红色/黑色),具体如下所示: ```java private static final boolean RED = false; private static final boolean BLACK = true; static class Node<K,V> { K key; // 存储的关键字 V value; // 对应关键字所映射的对象 Node<K,V> left; // 左孩子引用 Node<K,V> right; // 右孩子引用 Node<K,V> parent;// 父亲引用 boolean color; // 颜色标记 public Node(K key, V value, Node<K,V> parent){ this.key=key; this.value=value; this.parent=parent; this.color=RED; // 新加入的节点默认设为红色 } } ``` #### 插入操作逻辑 当向一棵已有的红黑树内添加新元素时,会先按照普通的 BST 方式找到合适的位置并创建新的叶子节点。之后再依据一系列规则判断是否需要执行重涂色或是旋转变换以恢复整棵树应有的形态特征。 - 如果当前新增加的是根,则直接将其变为黑色; - 若祖父存在且叔叔也为红色,则将父亲、叔叔均改为黑色并将祖父变更为红色继续向上处理; - 当仅有单侧兄弟呈红色状态时可通过一次左(右)转使得双亲成为临时性的“假”根以便后续统一调整; - 剩余情形下只需简单交换父子间染色即可完成修复工作。 以上过程可以概括成一段伪代码形式表示出来: ```pseudo function insertFixup(node) if node is root then set its color to black and return. while (node != null && node's parent is red) // 处理违反红黑树特性的几种场景... end while ``` 实际上完整的算法较为复杂,涉及到多个分支路径的选择问题,这里仅给出大致思路供理解参考之用。 #### 删除操作概述 移除某个指定项的过程同样遵循着相似的原则——即先依照普通二叉搜索树的方式定位目标对象所在位置,并考虑三种不同类型的状况分别采取相应的措施加以应对:如果待消除的目标恰好处于末端处那么可以直接摘掉它而不影响其他部分;反之则需寻找合适的替代品填补空缺后再做进一步讨论。 值得注意的是在整个过程中可能会引入一些暂时不符合标准的情况,这就要求我们及时作出必要的修正动作直至最终达到稳定为止。 #### 应用实例分析 正如前面提及的一样,红黑树广泛应用于各种编程语言的标准库当中作为内部机制支撑起诸如有序表之类的抽象容器类型。例如在 JDK8 版本以后版本里头,`HashMap` 的链地址法解决哈希冲突方案便采用了基于红黑树优化后的链表结构,以此提高极端情况下访问效率的同时兼顾了空间利用率方面的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值