跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 红黑树实现详解:规则、结构与核心操作

红黑树是一种自平衡二叉搜索树,通过颜色约束确保最长路径不超过最短路径的两倍。详细解析了红黑树的五条基本规则、节点结构设计以及插入操作的三种核心情况(变色、单旋、双旋)。内容涵盖查找与验证逻辑,并提供了完整的 C++ 代码实现,包括旋转函数与平衡性检测,适合深入理解底层数据结构原理及工程落地。

深海蔚蓝发布于 2026/3/15更新于 2026/10/2686 浏览
C++ 红黑树实现详解:规则、结构与核心操作

C++ 红黑树实现详解

一、红黑树的概念

红黑树是二叉搜索树的一种变体,每个节点增加一个颜色位(红或黑)。通过对从根到叶子路径上节点颜色的约束,确保没有一条路径比其他路径长出 2 倍,从而保持近似平衡。

1.1 红黑树的规则

  1. 每个节点不是红色就是黑色。
  2. 根节点是黑色的。
  3. 如果一个节点是红色的,则它的两个子节点必须是黑色的(即任意路径无连续红色节点)。
  4. 对于任意一个节点,从该节点到其所有 NULL 节点的简单路径上,均包含相同数量的黑色节点。

说明:《算法导论》等书籍补充了叶子节点(NIL)都是黑色的规则。这里的叶子节点指空节点,为了便于标识路径。实际实现中通常忽略 NIL 节点的具体存在,只需理解概念即可。

1.2 为什么最长路径不超过最短路径的 2 倍?

  • 最短路径:全是黑色节点,长度为黑高 bh。
  • 最长路径:一黑一红间隔组成,长度为 2*bh。
  • 结论:综合规则可知,任意路径长度 x 满足 bh <= x <= 2*bh。

1.3 红黑树的效率

假设 N 为节点数量,h 为最短路径长度,则 2^h - 1 <= N < 2^(2*h) - 1。由此推出 h ≈ logN。这意味着红黑树增删查改的最坏时间复杂度仍为 O(logN)。相比 AVL 树,红黑树对平衡控制没那么严格,插入时旋转次数更少,整体效率在同一档次。

二、红黑树的实现

2.1 红黑树的结构

我们需要在二叉搜索树节点基础上增加父指针和颜色属性,以便处理旋转和变色逻辑。

enum Colour { RED, BLACK };

template<class K, class V>
struct RBTreeNode {
    pair<K, V> _kv;
    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;
    Colour _col;

    RBTreeNode(const pair<K, V>& kv)
        :_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED) {}
};

template<class K, class V>
class RBTree {
    typedef RBTreeNode<K, V> Node;
public:
    // ... 具体方法见完整代码
private:
    Node* _root = ;
};
nullptr

2.2 红黑树的插入

插入过程遵循二叉搜索树规则,随后检查并修复红黑性质。

  1. 空树插入:新增节点设为黑色。
  2. 非空树插入:新增节点必须为红色。若父节点为黑色,无需调整;若父节点为红色,则违反规则 3,需调整。
  3. 调整策略:根据叔叔节点(Uncle)的颜色分情况处理。
情况 1:变色
  • 条件:叔叔节点存在且为红色。
  • 操作:父节点和叔叔节点变黑,祖父节点变红。将祖父节点视为当前节点继续向上处理。
  • 注意:若祖父节点变为根节点,需将其重新染黑。
情况 2:单旋 + 变色
  • 条件:叔叔节点不存在或为黑色,且当前节点与父节点同侧(左左或右右)。
  • 操作:以祖父节点为支点进行单旋,父节点变黑,祖父节点变红。
情况 3:双旋 + 变色
  • 条件:叔叔节点不存在或为黑色,且当前节点与父节点异侧(左右或右左)。
  • 操作:先以父节点为支点单旋,再以祖父节点为支点反向单旋,最后调整颜色。

2.3 红黑树的查找

按二叉搜索树逻辑实现,效率为 O(logN)。

2.4 红黑树的验证

验证需检查四条规则:

  1. 颜色合法(红/黑)。
  2. 根节点为黑。
  3. 无连续红节点(遍历检查父节点)。
  4. 每条路径黑节点数相同(前序遍历记录黑高)。

2.5 红黑树的删除

删除操作较为复杂,涉及多种情况下的旋转与变色,本章节暂不展开,建议参考《算法导论》或《STL 源码剖析》。

三、完整代码

以下是完整的红黑树及对比用的 AVL 树实现,包含插入、旋转、验证及测试逻辑。

RBTree.h

#pragma once
#include <iostream>
using namespace std;

enum Colour { RED, BLACK };

template<class K, class V>
struct RBTreeNode {
    pair<K, V> _kv;
    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;
    Colour _col;

    RBTreeNode(const pair<K, V>& kv)
        :_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED) {}
};

template<class K, class V>
class RBTree {
    typedef RBTreeNode<K, V> Node;
public:
    bool Insert(const pair<K, V>& kv) {
        if (_root == nullptr) {
            _root = new Node(kv);
            _root->_col = BLACK;
            return true;
        }

        Node* parent = nullptr;
        Node* cur = _root;
        while (cur) {
            if (cur->_kv.first < kv.first) {
                parent = cur;
                cur = cur->_right;
            } else if (cur->_kv.first > kv.first) {
                parent = cur;
                cur = cur->_left;
            } else {
                return false; // 重复键值
            }
        }

        cur = new Node(kv);
        cur->_col = RED;
        if (parent->_kv.first < kv.first) {
            parent->_right = cur;
        } else {
            parent->_left = cur;
        }
        cur->_parent = parent;

        while (parent && parent->_col == RED) {
            Node* grandfather = parent->_parent;
            if (grandfather->_left == parent) {
                Node* uncle = grandfather->_right;
                // 情况一:叔叔存在且为红
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    cur = grandfather;
                    parent = cur->_parent;
                } else {
                    // 情况二:叔叔不存在或为黑
                    if (cur == parent->_left) {
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            } else {
                Node* uncle = grandfather->_left;
                // 情况一:叔叔存在且为红
                if (uncle && uncle->_col == RED) {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    cur = grandfather;
                    parent = cur->_parent;
                } else {
                    // 情况二:叔叔不存在或为黑
                    if (cur == parent->_right) {
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    } else {
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
        }
        _root->_col = BLACK;
        return true;
    }

    void InOrder() {
        _InOrder(_root);
        cout << endl;
    }

    bool Check(Node* root, int blackNum, const int refNum) {
        if (root == nullptr) {
            if (refNum != blackNum) {
                cout << "存在黑色结点的数量不相等的路径" << endl;
                return false;
            }
            return true;
        }
        if (root->_col == RED && root->_parent->_col == RED) {
            cout << root->_kv.first << "存在连续的红色结点" << endl;
            return false;
        }
        if (root->_col == BLACK) {
            blackNum++;
        }
        return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
    }

    bool IsBalance() {
        if (_root == nullptr) return true;
        if (_root->_col == RED) return false;
        int refNum = 0;
        Node* cur = _root;
        while (cur) {
            if (cur->_col == BLACK) ++refNum;
            cur = cur->_left;
        }
        return Check(_root, 0, refNum);
    }

    int Height() { return _Height(_root); }
    int Size() { return _Size(_root); }

    Node* Find(const K& key) {
        Node* cur = _root;
        while (cur) {
            if (cur->_kv.first < key) cur = cur->_right;
            else if (cur->_kv.first > key) cur = cur->_left;
            else return cur;
        }
        return nullptr;
    }

protected:
    int _Size(Node* root) {
        if (root == nullptr) return 0;
        return _Size(root->_left) + _Size(root->_right) + 1;
    }

    int _Height(Node* root) {
        if (root == nullptr) return 0;
        int leftHeight = _Height(root->_left);
        int rightHeight = _Height(root->_right);
        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }

    void RotateR(Node* parent) {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR) subLR->_parent = parent;
        Node* ppNode = parent->_parent;
        subL->_right = parent;
        parent->_parent = subL;
        if (parent == _root) {
            _root = subL;
            subL->_parent = nullptr;
        } else {
            if (ppNode->_left == parent) ppNode->_left = subL;
            else ppNode->_right = subL;
            subL->_parent = ppNode;
        }
    }

    void RotateL(Node* parent) {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if (subRL) subRL->_parent = parent;
        Node* parentParent = parent->_parent;
        subR->_left = parent;
        parent->_parent = subR;
        if (parentParent == nullptr) {
            _root = subR;
            subR->_parent = nullptr;
        } else {
            if (parent == parentParent->_left) parentParent->_left = subR;
            else parentParent->_right = subR;
            subR->_parent = parentParent;
        }
    }

    void _InOrder(Node* root) {
        if (root == nullptr) return;
        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }

private:
    Node* _root = nullptr;
};

AVLTree.h

#pragma once
#include <iostream>
#include <cmath>
using namespace std;

template<class K, class V>
struct AVLTreeNode {
    pair<K, V> _kv;
    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;
    int _bf;

    AVLTreeNode(const pair<K, V>& kv)
        :_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr), _bf(0) {}
};

template<class K, class V>
class AVLTree {
    typedef AVLTreeNode<K, V> Node;
public:
    bool Insert(const pair<K, V>& kv) {
        if (_root == nullptr) {
            _root = new Node(kv);
            return true;
        }
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur) {
            if (cur->_kv.first < kv.first) {
                parent = cur;
                cur = cur->_right;
            } else if (cur->_kv.first > kv.first) {
                parent = cur;
                cur = cur->_left;
            } else {
                return false;
            }
        }
        cur = new Node(kv);
        if (parent->_kv.first < kv.first) parent->_right = cur;
        else parent->_left = cur;
        cur->_parent = parent;

        while (parent) {
            if (cur == parent->_right) parent->_bf++;
            else parent->_bf--;

            if (parent->_bf == 0) break;
            else if (abs(parent->_bf) == 1) {
                cur = parent;
                parent = parent->_parent;
            } else {
                if (parent->_bf == -2 && cur->_bf == -1) RotateR(parent);
                else if (parent->_bf == 2 && cur->_bf == 1) RotateL(parent);
                else if (parent->_bf == -2 && cur->_bf == 1) RotateLR(parent);
                else if (parent->_bf == 2 && cur->_bf == -1) RotateRL(parent);
                else assert(false);
                break;
            }
        }
        return true;
    }

    void InOrder() { _InOrder(_root); cout << endl; }
    bool IsBalanceTree() { return _IsBalanceTree(_root); }
    Node* Find(const K& key) {
        Node* cur = _root;
        while (cur) {
            if (cur->_kv.first < key) cur = cur->_right;
            else if (cur->_kv.first > key) cur = cur->_left;
            else return cur;
        }
        return nullptr;
    }
    int Height() { return _Height(_root); }
    int Size() { return _Size(_root); }

private:
    int _Size(Node* root) {
        if (root == nullptr) return 0;
        return _Size(root->_left) + _Size(root->_right) + 1;
    }
    bool _IsBalanceTree(Node* root) {
        if (nullptr == root) return true;
        int leftHeight = _Height(root->_left);
        int rightHeight = _Height(root->_right);
        int diff = rightHeight - leftHeight;
        if (abs(diff) >= 2 || root->_bf != diff) {
            cout << root->_kv.first << "高度差异常" << endl;
            return false;
        }
        return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
    }
    int _Height(Node* root) {
        if (root == nullptr) return 0;
        int leftHeight = _Height(root->_left);
        int rightHeight = _Height(root->_right);
        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }
    void _InOrder(Node* root) {
        if (root == nullptr) return;
        _InOrder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _InOrder(root->_right);
    }
    void RotateR(Node* parent) {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR) subLR->_parent = parent;
        Node* ppNode = parent->_parent;
        subL->_right = parent;
        parent->_parent = subL;
        if (parent == _root) {
            _root = subL;
            subL->_parent = nullptr;
        } else {
            if (ppNode->_left == parent) ppNode->_left = subL;
            else ppNode->_right = subL;
            subL->_parent = ppNode;
        }
        parent->_bf = 0;
        subL->_bf = 0;
    }
    void RotateL(Node* parent) {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if (subRL) subRL->_parent = parent;
        Node* parentParent = parent->_parent;
        subR->_left = parent;
        parent->_parent = subR;
        if (parentParent == nullptr) {
            _root = subR;
            subR->_parent = nullptr;
        } else {
            if (parent == parentParent->_left) parentParent->_left = subR;
            else parentParent->_right = subR;
            subR->_parent = parentParent;
        }
        parent->_bf = 0;
        subR->_bf = 0;
    }
    void RotateLR(Node* parent) {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;
        RotateL(parent->_left);
        RotateR(parent);
        if (bf == -1) { subL->_bf = 0; parent->_bf = 1; subLR->_bf = 0; }
        else if (bf == 1) { subL->_bf = -1; parent->_bf = 0; subLR->_bf = 0; }
        else { subL->_bf = 0; parent->_bf = 0; subLR->_bf = 0; }
    }
    void RotateRL(Node* parent) {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;
        RotateR(parent->_right);
        RotateL(parent);
        if (bf == 0) { subR->_bf = 0; subRL->_bf = 0; parent->_bf = 0; }
        else if (bf == 1) { subR->_bf = 0; subRL->_bf = 0; parent->_bf = -1; }
        else if (bf == -1) { subR->_bf = 1; subRL->_bf = 0; parent->_bf = 0; }
    }

private:
    Node* _root = nullptr;
};

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<assert.h>
#include<time.h>
#include"RBTree.h"
#include"AVLTree.h"
using namespace std;

void TestRBTree1() {
    RBTree<int, int> t;
    int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    for (auto e : a) {
        t.Insert({ e, e });
        cout << "Insert:" << e << "->" << t.IsBalance() << endl;
    }
    t.InOrder();
}

void TestRBTree2() {
    const int N = 10000000;
    vector<int> v;
    v.reserve(N);
    srand(time(0));
    for (size_t i = 0; i < N; i++) {
        v.push_back(rand() + i);
    }
    size_t begin2 = clock();
    RBTree<int, int> t;
    for (auto e : v) {
        t.Insert(make_pair(e, e));
    }
    size_t end2 = clock();
    cout << t.IsBalance() << endl;
    cout << "RBTree Insert:" << end2 - begin2 << endl;
    cout << "RBTree Height:" << t.Height() << endl;
    cout << "RBTree Size:" << t.Size() << endl;
    size_t begin1 = clock();
    for (size_t i = 0; i < N; i++) {
        t.Find((rand() + i));
    }
    size_t end1 = clock();
    cout << "RBTree Find:" << end1 - begin1 << endl << endl;
}

int main() {
    TestRBTree2();
    return 0;
}

目录

  1. C++ 红黑树实现详解
  2. 一、红黑树的概念
  3. 1.1 红黑树的规则
  4. 1.2 为什么最长路径不超过最短路径的 2 倍?
  5. 1.3 红黑树的效率
  6. 二、红黑树的实现
  7. 2.1 红黑树的结构
  8. 2.2 红黑树的插入
  9. 情况 1:变色
  10. 情况 2:单旋 + 变色
  11. 情况 3:双旋 + 变色
  12. 2.3 红黑树的查找
  13. 2.4 红黑树的验证
  14. 2.5 红黑树的删除
  15. 三、完整代码
  16. RBTree.h
  17. AVLTree.h
  18. test.cpp

更多推荐文章

查看全部
  • 宇树 G1 机器人开发入门:有线与无线连接完整指南
  • 一种光伏产品缺陷检测 AI 深度学习算法
  • Dify 本地部署大模型智能体:Skill 开发与企业级落地实践
  • C++ 虚函数、多态与对象内存布局
  • OpenRFT:基于强化微调实现大模型领域推理泛化
  • MySQL 8.4.7 Windows 免安装版部署与配置详解
  • Android 应用安全加固与防破解措施分析
  • PostCSS px-to-viewport 移动端适配配置指南
  • Qwen3.5-9B 如何以 1/13 参数量超越 GPT-oss-120B?架构与性能实测
  • 大模型应用:新时代的多模态交互
  • Win11 安装 Node.js 后 npm install 报错:禁止运行脚本
  • LLaMA-Factory 微调 Qwen3-VL 详细流程
  • 高云 FPGA 远程升级原理
  • Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码
  • VSCode Copilot 接入智谱 GLM-4.6 及其他大模型配置指南
  • C++ STL vector 容器模拟实现及迭代器失效问题详解
  • 国产 FPGA 低温低压测试问题反思与总结
  • FPGA 入门实战:从零点亮 LED
  • 基于 LangChain 的 LLM Graph Builder 构建知识图谱实战
  • Vue3 + PlayCanvas 实战:3D 地图自由巡视闯关游戏开发

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online