红 黑 树

article/2025/8/29 1:21:25

AVL树是严格平衡的。

红⿊树是⼀棵⼆叉搜索树。 通过对任何⼀条从根到叶⼦的路径上各个结点的颜⾊进⾏约束,红⿊树确保没有⼀条路径会⽐其他路径⻓出2倍,因⽽是接近平衡的。即最长路径<=最短路径的2倍。

红黑树规则:

1. 每个结点不是红⾊就是⿊⾊

2. 根结点是⿊⾊的

3. 如果⼀个结点是红⾊的,则它的两个孩⼦结点必须是⿊⾊的,也就是说任意⼀条路径不会有连续的 红⾊结点。即不存在连续红色的。

4. 对于任意⼀个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的⿊⾊结点。即每条路径的黑色节点的个数相等。(比较严格)

新插入节点插入红色。如果插入黑色就一定会违反规则4,因为规则4比较严格,所以不要破坏规则4。

 红黑树的抽象图:

情况一:cur是新增节点,cur是红,p是红,u是红且存在,g是黑。

变换规则是:

 

代码如下所示:

	//1.叔叔存在且是红。p变黑,u变黑,g变红。如果g是根再次变黑,否则继续向上更新。if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = parent;//继续向上更新parent = cur->_parent;}//2.叔叔不存在/存在且是黑else{if (cur == parent->_left)//单旋{//     g                 p//   p   u------>     c    g// c                          uRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else//双旋{//      g                 g            c//   p     u    ->      c    u   ->  p     g//      c             p                        uRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}
}

情况二:cur是新增节点,cur是红,p是红,g是黑,u不存在/存在且为黑。

 情况二还有一种情况是双旋+变色。具体的实现代码如下所示:

	//2.叔叔不存在/存在且是黑
else
{if (cur == parent->_left)//单旋{//     g                 p//   p   u------>     c    g// c                          uRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else//双旋{//      g                 g            c//   p     u    ->      c    u   ->  p     g//      c             p                        uRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;
}

 整体代码如下:

enum Colour
{RED,BLACK
};
template<class K,class T>
struct RBTreeNode {RBTreeNode<K, T>* _left;RBTreeNode<K, T>* _right;RBTreeNode<K, T>* _parent;pair<K, T> _kv;Colour _col;RBTreeNode(const pair<K, T>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_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* cur = _root;Node* parent = nullptr;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;//当父亲不为空且父亲是红色的时候,关键是看叔叔,分两种情况:1.叔叔存在且是红。2.叔叔不存在/存在且是黑while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left)//叔叔在爷爷的右边{Node* uncle = grandfather->_right;//1.叔叔存在且是红。p变黑,u变黑,g变红。如果g是根再次变黑,否则继续向上更新。if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = parent;//继续向上更新parent = cur->_parent;}//2.叔叔不存在/存在且是黑else{if (cur == parent->_left)//单旋{//     g                 p//   p   u------>     c    g// c                          uRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else//双旋{//      g                 g            c//   p     u    ->      c    u   ->  p     g//      c             p                        uRotateL(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 // 叔叔不存在,或者存在且为黑{// 情况二:叔叔不存在或者存在且为黑// 旋转+变色//      g//   u     p//            cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//		g//   u     p//      cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}void RotateR(Node* parent)//右旋{Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* ppNode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_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;subR->_left = parent;Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_right == parent){ppNode->_right = subR;}else{ppNode->_left = subR;}subR->_parent = ppNode;}}bool IsBalance()//判断是否平衡,满足规则。{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);}private:bool Check(Node* root, int blackNum, const int refNum)//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);}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;
};

http://www.hkcw.cn/article/GWCnagEsEd.shtml

相关文章

[ Qt ] | Qlabel使用

目录 属性 setTextFormat 插入图片 设置图片根据窗口大小实时变化 边框和对其方式 ​编辑 设置缩进 设置伙伴 Qlabel可以用来显式图片和文字 属性 text textFormat Qlabel独有的机制&#xff1a;buddy setTextFormat 插入图片 设置图片根据窗口大小实时变化 Qt中表…

智能座舱产品安全标准

目录 一、导览 二、意向 一、导览 国内近几年的电动汽车发展迅速&#xff0c;2024年4月16日&#xff0c;工信部装备工业一司组织主要汽车生产企业、部装备工业发展中心等近60名代表召开专题会议&#xff0c;重点落实《关于进一步加强智能网联汽车产品准入、召回及软件在线升级…

责任链模式:构建灵活可扩展的请求处理体系(Java 实现详解)

一、责任链模式核心概念解析 &#xff08;一&#xff09;模式定义与本质 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是将多个处理者对象连成一条链&#xff0c;并沿着这条链传递请求&#xff0c;直到有某…

Sentieon项目文章 | 社区努力识别和纠正蛋白质基因组研究中标签错误的样本

关键词&#xff1a;多组学&#xff1b;蛋白质&#xff1b;错误标记&#xff1b; 引言 在日常生活中&#xff0c;会经常遇到物品与标签错误的问题&#xff0c;比如超市商品标价错误、图书馆书籍分类错误等。都会造成一些后果。在生物医学研究领域中&#xff0c;蛋白质样本标记错…

git reset --hard HEAD~1与git reset --hard origin/xxx

git reset --hard HEAD~1与git reset --hard origin/xxx git reset --hard origin/xxx有时候会太长&#xff0c;手工输入略微繁琐&#xff0c;可以考虑&#xff1a; git reset --hard HEAD~1 替代。 或者使用这种方式 git reset撤销当前分支所有修改&#xff0c;恢复到最近一…

Kotlin委托机制使用方式和原理

目录 类委托属性委托简单的实现属性委托Kotlin标准库中提供的几个委托延迟属性LazyLazy委托参数可观察属性Observable委托vetoable委托属性储存在Map中 实践方式双击back退出Fragment/Activity传参ViewBinding和委托 类委托 类委托有点类似于Java中的代理模式 interface Base…

2025年能源科学与农业发展国际会议:共创可持续农业未来

会议简介 第二届能源环境科学与农业发展国际会议即将在武汉盛大召开。此次盛会定于武汉这一中部地区的中心城市举办&#xff0c;旨在汇聚国内外能源环境科学与农业发展的专家学者、企业家及各界精英&#xff0c;共同探讨能源资源的高效利用、环境保护的科技创新以及农业可持续发…

MongoDB(七) - MongoDB副本集安装与配置

文章目录 前言一、下载MongoDB1. 下载MongoDB2. 上传安装包3. 创建相关目录 二、安装配置MongoDB1. 解压MongoDB安装包2. 重命名MongoDB文件夹名称3. 修改配置文件4. 分发MongoDB文件夹5. 配置环境变量6. 启动副本集7. 进入MongoDB客户端8. 初始化副本集8.1 初始化副本集8.2 添…

未来楼宇自控系统升级优化,为绿色建筑发展注入更强动力支撑

在全球积极应对气候变化、大力推进节能减排的时代背景下&#xff0c;建筑行业作为能源消耗和碳排放的重点领域&#xff0c;其绿色转型迫在眉睫。绿色建筑旨在减少对环境的负面影响&#xff0c;实现资源高效利用&#xff0c;而楼宇自控系统作为建筑智能化的核心组成部分&#xf…

【SQL Server Management Studio 连接时遇到的一个错误】

第一次用SQL Server Management Studio启动之后第一步就是要建立连接 但是不知道Server Name要填什么&#xff0c;看了网上的教程说是要找到下面这个注册表中对应的实例名称填上去&#xff0c;或者前面加localhost 但是好像都没有用&#xff0c;一直遇到报错如下&#xff1a;…

华为云Flexus+DeepSeek征文 | 初探华为云ModelArts Studio:部署DeepSeek-V3/R1商用服务的详细步骤

华为云FlexusDeepSeek征文 | 初探华为云ModelArts Studio&#xff1a;部署DeepSeek-V3/R1商用服务的详细步骤 前言一、华为云ModelArts Studio平台介绍1.1 ModelArts Studio介绍1.2 ModelArts Studio主要特点1.3 ModelArts Studio使用场景1.4 ModelArts Studio产品架构 二、访问…

【Redis】string 类型

string 一. string 类型介绍二. string 命令set、getmget、msetsetnx、setex、psetexincr、incrby、decr、decrby、incrbyfloatappend、getrange、setrange、strlen 三. string 命令小结四. string 内部编码方式五. string 的应用场景缓存功能计数功能共享会话手机验证码 六. 什…

字体查看器

为了快速找到0不带点、斜杠的等宽字体&#xff0c;我做了个软件&#xff01; sonichy/HTYFontViewer

Java与Python优劣分析及两者联姻收奇功

Python 和 Java 作为两种广泛使用的编程语言&#xff0c;在大多数场景下都能实现相似的功能。但由于语言设计初衷、生态系统以及社区偏好的不同&#xff0c;Python 在某些特定领域确实具有 Java 难以比拟的天然优势。 一、以下是几个典型场景优劣分析 1. 快速原型开发与脚本化…

6.OpenFeign服务接口调用

目录 OpenFeign服务接口调用 一、openFeign简介 二、、OpenFeign 通用步骤 接口注解 流程步骤 1. 建Module 2. 添加POM依赖 3. 编写YML文件 4. 主启动(修改类名为MainOpenFeign80) 5.OpenFeign业务类编写 测试&#xff08;远程调用&#xff09; 三、OpenFeign高级特…

新能源汽车电控系统的精准守护者PKDV5355高压差分探头

在新能源汽车的"心脏"——电控系统中&#xff0c;每一次电流的精准切换都关乎车辆的性能与安全。PRBTEK PKDV5355高压差分探头就像一位经验丰富的"汽车医生"&#xff0c;帮助工程师们精准捕捉IGBT模块的每一次"心跳"&#xff0c;确保电驱系统健康…

资产生命周期管理:动态监控 + 精准管理

在数字化高度发展的当下&#xff0c;企业资产的范畴早已突破传统固定资产的局限&#xff0c;网络设备、服务器、软件系统等数字化资产在企业的日常运营与战略布局中扮演着越来越重要的角色。高效的资产管理体系对于优化资源配置、降低运营成本、确保业务不间断运行至关重要。 北…

MonoPCC:用于内窥镜图像单目深度估计的光度不变循环约束|文献速递-深度学习医疗AI最新文献

Title 题目 MonoPCC: Photometric-invariant cycle constraint for monocular depth estimation of endoscopic images MonoPCC&#xff1a;用于内窥镜图像单目深度估计的光度不变循环约束 01 文献速递介绍 单目内窥镜是胃肠诊断和手术的关键医学成像工具&#xff0c;但其…

华为OD机试真题——找终点(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

电路图识图基础知识-电路接线图(八)

识读电路接线图常识 1 电路接线图与电气原理图之间的关系 电气接线图是表示电气设备、元器件或装置等项目之间的连接关系&#xff0c;用来进行安装接线、 线路检查、线路检修和故障处理的一种简图。 在绘制电路接线图时必须依据相应的电气原理图&#xff0c;电路接线后必须达到…