前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++红黑树的深入解析:从理论到实践

C++红黑树的深入解析:从理论到实践

作者头像
用户11289931
发布于 2025-03-20 05:58:46
发布于 2025-03-20 05:58:46
12000
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

红黑树作为一种自平衡的二叉搜索树,是计算机科学中的经典数据结构之一,广泛应用于各种需要高效查找、插入和删除操作的场景中,比如STL中的 mapset。虽然它的基本原理并不复杂,但在实现过程中,需要处理许多细节,比如颜色的调整、旋转操作等。本文将对红黑树的结构、插入、删除等操作进行详细的剖析,以帮助大家更好地理解和实现这一高效的数据结构。

一、红黑树的基本概念与规则

红黑树是一种满足特定性质的二叉搜索树。与普通的二叉搜索树不同,红黑树的每个结点都附加了一个颜色属性,且通过一些规则保证了树的平衡性。红黑树的四条基本规则如下:

  1. 每个节点的颜色要么是红色,要么是黑色。
  2. 根节点是黑色的。
  3. 如果一个节点是红色的,那么它的两个子节点必须是黑色的。 这就意味着红色节点不能有连续的红色节点。
  4. 从任意一个节点到其所有叶子节点的路径上,必须包含相同数量的黑色节点。 这条规则保证了树的平衡性,防止树的某些路径过长。

红黑树的这些规则通过“颜色约束”来间接实现自平衡,因此每次进行插入、删除操作时,都需要确保这些规则被满足。

以上均为红黑树示例。

二、红黑树的高度与效率

红黑树的高度是它的关键特性之一。红黑树的自平衡机制确保了它的高度不会太大,这对于树的查找、插入和删除操作的效率至关重要。理论上,红黑树的高度 h 与黑色高度 bh(从根到叶子节点的路径上黑色节点的数量)之间存在如下关系:

  • 最短路径(只有黑色节点)长度为 bh。
  • 最长路径(交替的红色和黑色节点)长度为 2 * bh。

因此,红黑树的最大高度为 2 * bh,而最小高度为 bh。因此,红黑树的高度 h 满足 h≤2×bhh \leq 2 \times bhh≤2×bh,并且由于红黑树的黑色高度是相同的,所以可以得出红黑树的高度是 O(log N),其中 N 是树中结点的数量。

由于红黑树的高度被控制在对数级别,它能够保证查找、插入、删除操作在最坏情况下的时间复杂度均为 O(log N)。

三、红黑树的结构

红黑树的基本节点结构包括以下几个部分:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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) {}
};

每个节点不仅包含键值对 (_kv),还包含指向左子树、右子树和父节点的指针。此外,节点的颜色 (_col) 用于维护红黑树的平衡。

四、红黑树的插入操作

红黑树的插入操作需要遵循以下步骤:

  1. 按照二叉搜索树的规则插入新节点。这是插入操作的第一步,我们首先将新节点插入到树的适当位置。
  2. 将新节点的颜色设置为红色。新插入的节点默认是红色的,这有助于避免违反红黑树的黑色节点数平衡。
  3. 调整颜色和结构。插入新节点后,可能会破坏红黑树的平衡。具体的修复操作包括:
    • 情况1:变色操作。如果父节点和叔叔节点都是红色,则将父节点和叔叔节点都变为黑色,祖父节点变为红色,并继续往上处理。
    • 情况2:旋转和变色。如果父节点是红色,且叔叔节点是黑色或不存在,则需要进行旋转操作(单旋或双旋),并相应地调整颜色。

我们来看一段插入代码的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 (parent == grandfather->_left) {
            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;
}

这段代码展示了红黑树的插入操作,包括节点插入、颜色变更和旋转操作。关键的操作是通过循环和条件判断来确保红黑树的规则不被破坏。

五、红黑树的查找操作

红黑树的查找操作和普通的二叉搜索树是类似的,我们依然按照二叉搜索树的规则进行查找。由于红黑树的平衡性,查找操作的时间复杂度为 O(log N)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
}

上述代码展示了查找操作的实现,我们根据节点的键值逐步向左或向右子树移动,直到找到目标节点或树为空。

六、红黑树的删除操作

删除操作在红黑树中比插入操作更为复杂。删除一个节点后,可能会破坏红黑树的平衡,特别是当删除的节点是黑色时,需要特别注意。因此,删除操作需要执行旋转和变色操作来恢复平衡。尽管删除操作复杂,但其时间复杂度同样是 O(log N)。

由于删除操作较为复杂,本文不深入讨论其实现。如果有兴趣,可以参考《算法导论》或《STL源码剖析》中的相关章节。

七、红黑树的验证

为了验证红黑树的正确性,我们可以检查它是否满足四条基本规则。可以通过前序遍历树的每一条路径,检查节点颜色和黑色节点数量是否符合要求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
}

通过这个检查函数,我们能够验证树的结构是否符合红黑树的规则。

八、总结

红黑树是一种自平衡的二叉搜索树,通过简单的规则保证树的平衡性,确保了查找、插入和删除操作的时间复杂度始终为 O(log N)。虽然红黑树的插入、删除操作相对复杂,但它的高效性和稳定性使其成为许多应用中不可或缺的数据结构。希望通过本文的详细解析,大家能够对红黑树有更深入的了解。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
数据与日志相关问题
通过站点加速访问日志EdgeResponseBytes字段中记录的字节数统计而来的流量数据与控制台展示的流量数据、计费流量数据可能不一致。原因如下:
EdgeOne小助手
2024/08/27
1330
域名业务出现异常盗刷、攻击怎么办?
在激烈的市场竞争中,部分企业为了获取不正当的竞争优势,可能会采取恶意竞争手段。其中,通过攻击或盗刷竞争对手的业务,干扰其正常服务的提供,便是一种恶劣的行径。这种行为旨在破坏对方的业务稳定性和声誉,从而使自己在市场竞争中占据有利地位。
杜志强
2024/11/29
2550
域名业务出现异常盗刷、攻击怎么办?
计算回源带宽突增是有哪些大流量url导致
下载回源日志:http://admin.cdn.oa.com/tools/hy_log_url.html
Black_bd
2020/10/28
1.4K0
腾讯云产品使用指南(2024)
如果通过快速配置的方式进行购买云服务器,云服务器的初始密码将会以电子邮件和控制台站内信发送给您。
腾讯产业互联网学堂1
2024/03/04
4960
腾讯云产品使用指南(2024)
腾讯云cdn问题 Q&A
假设您的业务源站域名为www.test.com,域名接入 CDN 开始使用加速服务后,当您的用户发起 HTTP 请求时,实际的处理流程如下图所示:
杜志强
2019/03/06
11.8K0
腾讯云cdn问题 Q&A
IDC、友商云数据上云(COS)最佳实践
本文从通用的数据上云场景,以及友商云数据迁移场景出发,介绍基于腾讯云对象存储(COS)的上云步骤,包括迁移前的环境准备工作,云上的配置与迁移工具的实施,数据的一致性校验,云上业务的切换与验证。
wainsun
2021/08/18
2.4K0
IDC、友商云数据上云(COS)最佳实践
腾讯云2024双11大促:边缘安全加速平台EdgeOne最佳实践
腾讯云2024双11大促已正式开始,在这场活动中,腾讯云为用户带来了超值福利,其中就包括被称为下一代CDN的边缘安全加速平台EdgeOne,那么如何正确地配置、管理EdgeOne,以确保其安全稳定运行呢?
参谋带个长
2024/11/11
2.7K0
腾讯云2024双11大促:边缘安全加速平台EdgeOne最佳实践
实时音视频开发学习15 - 计费问题
腾讯云计费方式分为基础计费、增值服务计费和免费试用。其中基础计费包括语音通话额直播、视频通话和直播,增值服务主要为云端录制,采用旁路直播推流的方式使用云直播的能力并提供全程录制功能,录制的文件可以存储到云点播平台。
金林学音视频
2020/08/30
2.4K0
COS+CVM+CDN 实现低成本高效率往返传输数据
比如有这样的情况,客户是专门做影视的,渲染服务器在国内,拍摄组分布在欧洲各地,每天产生的数据高达500G,需要传到云服务器进行转码渲染,处理后数据差不多300G,然后再传回本地做备份
Ar-Sr-Na
2022/08/04
4.5K2
COS+CVM+CDN 实现低成本高效率往返传输数据
只需三步,快速在 Serverless 架构部署 WordPress 项目
WordPress 是使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设属于自己的网站,也可以把 WordPress 当作一个内容管理系统(CMS)来使用。根据 W3techs 的统计,截至 2020 年 12 月,全球约 39.9% 的网站都使用 WordPress,无论是个人博客,还是官方网站,还是作为通用的内容管理系统,都可以通过 Wordpress 快速搭建,也是目前最流行的动态网站框架之一。 腾讯云 Serverless 提供了基于 Serverles
腾讯云serverless团队
2021/02/01
1.5K1
如何使用图片压缩降低COS流量成本?
 导语 本文将介绍如何通过【图片压缩】能力,让您降本增效的使用 COS ,文章将写得浅显易懂,旨在快速带领用户了解图片压缩的用法及带来的收益。  图片压缩为什么会让您降本增效? 随着互联网业务量的不断
云存储
2023/03/29
1.7K0
如何使用图片压缩降低COS流量成本?
腾讯EdgeOne产品测评体验—Web服务全能一体化服务,主打一步到位
现在网络Web攻击真的防不胜防啊,相信有很多独狼开发者自己建站,租个云服务器,一部署自己的服务,每隔一段时间内测和网站总有一个要崩。自己感觉难受不说,网站稍微有点要出头的时候,数不清的访问攻击就接踵而至:恶意软件、SQL注入、网站挟持、钓鱼攻击、跨站脚本攻击、恶意爬虫等等,让个人开发者甚为揪心,如果是企业网站的话,攻势有过之无不及。
fanstuck
2024/04/16
2.2K1
腾讯EdgeOne产品测评体验—Web服务全能一体化服务,主打一步到位
cdn+cos完美结合
所以从流量的费用上来计算,最理想的状态(cdn缓存住所有数据,cos数据不进行更新),每GB可以节省0.29元。 当然,这只是极特殊情况;那么看下最坏的情况,cdn侧数据完全不缓存,通过cdn分发cos侧数据流量费用为:0.21(cdn访问流量)+0.15(cdn回源cos流量)=0.36元/GB,每GB也要节省0.14元。
杜志强
2019/12/18
6.7K1
cdn+cos完美结合
【玩转 EdgeOne】 使用EdgeOne实时日志+cls 自动生成网站访客信息
嗨,大家好,我是Eagle Yao。好久不见,我好久没有在这里分享我最近的一些体验。最近我看到了EdgeOne的征文活动,作为一名老用户,我觉得应该也要好好宣传一下EdgeOne的某一个产品。我是从个人版/基础版内测期间就开始使用EdgeOne,这半年来见证了EdgeOne的不断进步和完善,整体来说,我对腾讯云的新一代CDN非常满意。
鹰瑶
2023/10/04
8722
【参赛经验分享】腾讯云-云联网-全球互联技术实践文档
随着全球互联网络技术不断革新,全球云厂商地域互联需求增加,越来越多企业急需解决云端多地域内网互联,低时延,高通信等需求,腾讯云依据大量用户需求,推出【云联网】3.0产品。以下实践主要是利用腾讯云-云联网产品,打通全球VPC环境,实现内网互通,全球互联的实践技术文档。
TCS-F
2019/05/14
5.5K0
【参赛经验分享】腾讯云-云联网-全球互联技术实践文档
腾讯云消息队列5月产品月报 | CKafka 专业版支持弹性存储形态
自 2024年5月起,TDMQ CKafka 专业版支持弹性存储能力,这种产品形态下,存储可按需使用、按量付费,一方面降低消费即删除、存储使用波动大场景下的存储成本,另一方面存储空间理论上无穷大。
腾讯云中间件团队
2024/06/12
2530
腾讯云消息队列5月产品月报 |  CKafka 专业版支持弹性存储形态
如何使用对象存储 COS ?七个步骤,帮你搞定!
腾讯云对象存储 COS(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务,用户可通过网络随时存储和查看数据。同时为用户提供了高数据持久性、高可用性、高性能的对象存储服务。
云存储
2022/02/25
9.4K0
如何使用对象存储 COS ?七个步骤,帮你搞定!
[mit6.033] 第二部分 LEC 7-12 Networking 笔记
这一部分 Lecture 讲的内容,与计算机网络有一定重合,这里笔记偏向于在系统设计中需要考虑的概念,而至于具体的协议、网络通信的具体细节等,即使在 lecture 视频中提到了,也不会记录到笔记中。这一部分细节可以通过计算机网络课程学习。
Miigon
2022/10/27
3130
[mit6.033] 第二部分 LEC 7-12 Networking 笔记
腾讯云 Serverless 支撑「新东方」核心业务算力资源
谈起 Serverless 计算,在技术圈热度很高 —— 所有人都在说 Serverless,大家都声称在做 Serverless,但每个 Serverless 又不一样。我们不禁想问,Serverless 是不是只是一个炒热度的空洞热门词 ? 其实不然,Serverless 作为一种更易用、低成本、免运维的通用计算服务,已经在互联网核心业务中承担重要的算力角色,适用于各种计算应用场景。也正是因为其作为通用计算支撑,场景众多,业内使用 Serverless 计算的场景覆盖广泛,随处可见。 纵观国内 Se
腾讯云serverless团队
2020/08/05
1.7K0
【CLS日志服务 & SCF云函数实践】优雅地处理数据(超详细)
从上次SCF云函数API实践文章发布到现在已经过去3个月了,这篇文章主要介绍通过api快速操作scf,但是这篇文章并没有介绍如何处理scf产生的数据,本篇文章相当于是之前的续集,讨论cls处理scf的数据以及cls一个非常牛叉的功能,这里先按下不表。
Vapour
2023/10/25
6841
推荐阅读
相关推荐
数据与日志相关问题
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 一、红黑树的基本概念与规则
  • 二、红黑树的高度与效率
  • 三、红黑树的结构
  • 四、红黑树的插入操作
  • 五、红黑树的查找操作
  • 六、红黑树的删除操作
  • 七、红黑树的验证
  • 八、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档