C++进阶——红黑树

发布时间:2026/9/27 6:06:04

C++进阶——红黑树 一、红黑树的概念红黑树是一棵二叉搜索树他的每个节点增加一个数据来存储颜色可以是红色或者黑色。通过对任何一条从根到叶子的路径上各个结点的颜色进行约束红黑树确保没有一条路径会超出其他路径2倍的长度1.1 红黑树的规则每个节点不是红色就是黑色根节点是黑色的如果一个节点是红的他的孩子节点就是黑色的这意味着任意一条路径不能出现连续的红色节点对任意一个节点从该节点到其所有NULL节点的简单路径上均包含相同数量的黑色节点当我们能时刻满足这四条规则时我们就能确保树上没有一条路径会超出其他路径2倍的长度。1.2 红黑树的效率假设N是红黑树树中结点数量h是最短路径长度则2^h-1N2^(2*h)-1,由此推出h大约为logN也就意味着红黑树增删查改最坏也就是走最长路径2*logN那么时间复杂度还是OlogN红黑树的表达相对AVL树要抽象一些AVL树通过控制高度差直观地控制了平衡。红黑树通过4条规则的约束实现了近似平衡它们的效率都是同一档次但红黑树插入节点时旋转次数更少二、红黑树的实现2.1 红黑树的结构enum Color { RED, BLACK }; templateclass K,class V struct RBTreeNode { pairK, V _kv; Color _col; RBTreeNodeK, V* _parent; RBTreeNodeK, V* _left; RBTreeNodeK, V* _right; RBTreeNode(const pairK,V kv) :_kv(kv) ,_parent(nullptr) ,_left(nullptr) ,_right(nullptr) { } }; templateclass K,class V class RBTree { typedef RBTreeNodeK, V Node; public: RBTree(Node* rootnullptr) :_root(root) { } private: Node* _root; };2.2 红黑树的插入2.2.1 节点插入的大概过程插入一个值按二叉搜索树规则插入插入后只需观察是否符合红黑树的四条规则如果是空树插入新增节点是黑色节点。如果不是空树选中节点必须是红色节点若插入黑色节点会破坏规则4非空树插入后新增节点的父节点如果是黑色就未破坏规则插入结束若父节点是红色的则违反规则3。据下图c是红色p是红色g必为黑色2.2.2 情况1变色若c、p、u均为红色节点g为黑色节点就将p、u变黑g变红再将g变为新的c向上更新2.2.3 情况2单旋变色c、p为红g为黑u不存在或u为黑u不存在c必为新增节点因为若c为原来的g节点那么它因为孩子节点变色而变红原来是黑色节点但u的分支后面没有黑色节点了不满足每条分支黑色节点数量相等u存在且为黑c一定不是新增节点2.2.4 情况3双旋变色c、p为红g为黑u不存在或存在为黑2.3 红黑树的验证规则1枚举颜色类型天然保证了颜色只有黑色和红色规则2可直接验证规则3前序遍历检查遇到红色节点就查孩子不太方便可反过来检查父节点颜色前序遍历遍历时用形参记录当前节点到根黑色节点数量直到空节点再选任意一条路径黑色节点作为参考值依次比较三、全部实现代码#pragma once #includeiostream #includecassert using namespace std; enum Color { RED, BLACK }; templateclass K,class V struct RBTreeNode { pairK, V _kv; Color _col; RBTreeNodeK, V* _parent; RBTreeNodeK, V* _left; RBTreeNodeK, V* _right; RBTreeNode(const pairK,V kv) :_kv(kv) ,_parent(nullptr) ,_left(nullptr) ,_right(nullptr) { } }; templateclass K,class V class RBTree { typedef RBTreeNodeK, V Node; public: RBTree(Node* rootnullptr) :_root(root) { } bool Insert(const pairK, V kv) { Node* newnode new Node(kv); newnode-_col RED; if (_root nullptr) { newnode-_col BLACK; _root newnode; return true; } Node* pcur _root; Node* parent pcur; while (pcur) { parent pcur; if (pcur-_kv.first kv.first) pcur pcur-_right; else if (pcur-_kv.first kv.first) pcur pcur-_left; else { delete newnode; return false; } } //开始插入 pcur newnode; pcur-_parent parent; if (parent-_kv.first kv.first) parent-_left pcur; else parent-_right pcur; while (parent parent-_col ! BLACK) { Node* g parent-_parent; Node* u nullptr; if (g) { if (parent g-_left)u g-_right; else u g-_left; if (u u-_col RED g-_col BLACK)//情况1p、c、u、都是红色g为黑色 { parent-_col BLACK; u-_col BLACK; g-_col RED; pcur g; parent g-_parent; } else if (parentg-_leftpcurparent-_left)//情况2单旋变色 { RotateR(parent); parent-_col BLACK; g-_col RED; break; } else if (parent-_right pcur g-_right parent) { RotateL(parent); parent-_col BLACK; g-_col RED; break; } else if (parent-_rightpcurg-_leftparent)//情况三双旋变色 { RotateL(pcur); RotateR(pcur); pcur-_col BLACK; g-_col RED; break; } else if (parent-_left pcur g-_right parent) { RotateR(pcur); RotateL(pcur); pcur-_col BLACK; g-_col RED; break; } } } _root-_col BLACK; return true; } void Print(Node* root) { if (root nullptr) return; Print(root-_left); cout root-_kv.first : root-_kv.second ; Print(root-_right); } Node* root() { return _root; } Node* Find(const K key) { Node* pcur _root; while (pcur) { if (pcur-_kv.first key) pcur pcur-_left; else if (pcur-_kv.first key) pcur pcur-_right; else return pcur; } return nullptr; } bool Isrbtree(Node* root) { if (_root nullptr)return true; if (root-_col ! BLACK)return false; int refnum 0; Node* cur root; while (cur ! nullptr) { if (cur-_col BLACK)refnum; cur cur-_left; } return Preorder(root,0,refnum); } private: bool Preorder(Node* root, int num, const int ref) { if (root nullptr) { return num ref; } if (root-_col RED root-_parent-_col ! BLACK) { cout 出现连续红色节点 endl; return false; } if (root-_col BLACK) return Preorder(root-_left, num 1, ref) Preorder(root-_right, num 1, ref); if (root-_col RED) return Preorder(root-_left, num, ref) Preorder(root-_right, num, ref); } void RotateR(Node* cur) { Node* parent cur-_parent; Node* grandpa parent-_parent; parent-_left cur-_right; parent-_parent cur; if (cur-_right) cur-_right-_parent parent; if (grandpa) { if (grandpa-_right parent) grandpa-_right cur; else grandpa-_left cur; } else _root cur; cur-_parent grandpa; cur-_right parent; } void RotateL(Node* cur) { Node* parent cur-_parent; Node* grandpa parent-_parent; parent-_right cur-_left; parent-_parent cur; if (cur-_left) { cur-_left-_parent parent; } if (grandpa) { if (grandpa-_right parent) grandpa-_right cur; else grandpa-_left cur; } else _root cur; cur-_parent grandpa; cur-_left parent; } Node* _root; };
延伸阅读

更多相关文章

2026/9/27 6:06:04

3个坑揭秘:旅游类网站开发设计报告与建站报价避坑指南

3个坑揭秘:旅游类网站开发设计报告与建站报价避坑指南 改个需求建站公司拖一周,这不仅是体验差,更是安全隐患。很多老板拿到一份厚厚的旅游类网站开发设计报告,看着精美,实则漏洞百出。更坑的是, 建站报价…

2026/9/27 6:01:04

AD9361多片同步:内部本振与外部本振的相位误差实战选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/27 7:01:06

重庆建网站cqiezscom哪家好?3个坑避开备案难

重庆建网站cqiezscom哪家好?3个坑避开备案难 备案流程一头雾水,直接导致网站上线延期三个月。 别慌,选对重庆建网站cqiezscom哪家好,这问题能省一半精力。 今天把我在行业摸爬滚打10年的经验,拆解给你看。…

2026/9/27 7:01:06

不会代码也能做站:Wordpress动图主题落地最佳实践

不会代码也能做站:Wordpress动图主题落地最佳实践 自己完全不懂代码,却想快速拥有一个视觉效果炸裂、能吸引眼球的企业官网或内容站,这确实是很多创业者和小团队负责人的噩梦。你不需要去啃晦涩的HTML和CSS,也不需要花几万块找外包团队被…

2026/9/27 6:56:06

Manim 中文显示问题报错解决办法

使用Manim直接制作这种动画视频的话是不支持中文的,需要进行一些修改,效果如图所示。 但是修改的方案都太坑,经过自己不断的研究找到了一个比较简单实用的方法。 文章目录 源文件修改 代码修改 源文件修改 实用everuthing找到ctex_template.tex文件。 我这里的路径是D:\M…

2026/9/27 0:00:45

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/27 0:00:45

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/27 0:00:45

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/27 0:00:45

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/27 0:00:45

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/27 0:00:45

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/25 18:34:56

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑