在这里插入图片描述
各位大佬好,我是落羽!一个坚持不断学习进步的大学生。
如果您觉得我的文章有所帮助,欢迎多多互三分享交流,一起学习进步!

也欢迎关注我的blog主页: 落羽的落羽

一、红黑树的概念与规则

红黑树是一种更加特殊的平衡二叉搜索树,它在每个节点上增加一个存储位来表示 节点的颜色(红色或黑色) ,并通过几条规则确保树在插入和删除操作后仍然保持平衡。

红黑树有以下四条规则:

  1. 每个结点不是红色就是黑色
  2. 根结点是黑色的
  3. 如果一个结点是红色的,则它的两个孩子必须都是黑色的,也就是说任意一条路径上不会出现连续的红色结点(黑色结点的孩子颜色不做要求)
  4. 对于任意一个结点,从结点到这棵树所有空结点的简单路径上,均包含相同数量的黑色结点

依靠它的几条规则,从同一结点出发红黑树没有一条路径会比其他路径长出2倍,因而也是接近平衡的。这是因为,由于从根到空结点的每条路径都有相同数量的黑色结点,所以极限场景下,理论最短路径就是全是黑色结点的路径(设长度为bh),理论最长路径是一黑一红间隔组成,长度就是2bh了。也就是说,红黑树中任意一条从根到空结点的路径x,都有bh <= x <= 2bh,确保了红黑树最长路径不超过最短路径的2倍了。

假设N是红黑树中结点数量,h是最短路径长度,那么2h -1 <= N <= 22h -1 ,推出h约等于logN,红黑树增删查改最坏情况也就是走最长路径2*logN,时间复杂度还是O(logN)。

这些规则保证了红黑树的平衡性,使得树的高度保持在logN级别。相比于AVL树,红黑树的平衡结构可以说更加“松散”,AVL树严格要求了左右子树高度差不超过1,但红黑树只要路径长不超过2倍就行,但它们的效率还是相同的水平。

二、红黑树的实现

红黑树的结构

红黑树的基本结构,不需要AVL树的平衡因子,而需要一个颜色成员:
enum Color
{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;Color _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;
};

红黑树的插入

红黑树的插入新结点的过程是这样的:
  • 首先按照二叉搜索树的规则找到应插入的位置,插入后我们需要判断是否符合红黑树的规则。
  • 如果是空树插入,新增结点必须是黑色的,插入完成;如果是非空树插入,新增结点必须是红色的,因为如果非空树插入了黑色结点就会破坏规则4,这条规则是很难维护的。
  • 非空树插入红色结点后,如果父亲是黑色的,则不会破坏任何规则,插入完成。
  • 非空树插入红色结点后,如果父亲是红色的,就破坏了规则“红色结点的孩子必须是黑色”,此时需要下面进一步分析。

接下来,我们具体分析最后一条情况,又有几种场景。下面称新增结点为c,c的父亲为p,p的父亲为g,p的兄弟为u。c是红色的,p也是红色的,那么g一定是黑色的,这三者的颜色是确定的,所以关键是看u的状态(下图中只表示出cpgu结点,省略其他子树):

场景1:

u存在且为红色。这种场景下,c保持红色不变,使p和u都变成黑色,g变为红色。这样处理后,就能使包含p或u的路径的黑色结点数量保持一致。

场景2:

u存在且为黑色 或 u不存在。u不存在,则c一定是新增结点;u存在且为黑,则c一定不是新增结点,而是新增结点插入在了c的子树中通过场景1调整后使c变成了红色。

这两种情况下处理方式是一样的,需要旋转+变色处理,但是旋转变色的方式,和AVL树一样仍需分情况讨论:

  • p是g的左,c是p的左。以g为旋转点右单旋。然后把p变黑,g变红。如图
  • p是g的右,c是p的右。以g为旋转点左单旋。然后把p变黑,g变红。如图
  • p是g的左,c是p的右。先以p为旋转点左单旋,再以g为旋转点右单旋(左右双旋)。然后把c变黑,g变红。如图
  • p是g的右,c是p的左。先以p为旋转点右单旋,再以g为旋转点左单旋(右左双旋)。然后把c变黑,g变红。如图

红黑树的插入代码实现:

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;cur->_parent = parent;if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}while (parent && parent->_col == RED){Node* grandfather = parent->_parent;//p是g的左的情况if (parent == grandfather->_left){Node* uncle = grandfather->_right;//u存在且为红色//变色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//u不存在或存在为黑色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;}}//p是g的右的情况else{Node* uncle = grandfather->_left;//u存在且为红色//变色if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//u不存在或存在为黑色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;
}

红黑树的验证

验证我们的红黑树是否合格,也就需要检查是否满足了那四条规则
  • 规则1不用检查,因为我们一开始就用了枚举类型赋值
  • 规则2检查根结点颜色即可
  • 规则3进行前序遍历,遇到红色结点就检查它的父结点是不是红色的
  • 规则4,首先用一个refNum记录最左路径的黑色结点数量,进行前序遍历,遍历过程中用一个变量blackNum记录到当前结点的黑色结点数量,遇到黑色结点就++blackNum,走到空就计算出了一条路径的黑色结点数量。此时若blackNum与refNum不同,则规则4不满足。
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 << "存在连续的红色结点!" << 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;}//参考值refNum记录最左路径的黑色结点数量int refNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){refNum++;}cur = cur->_left;}return Check(_root, 0, refNum);
}

本篇完,感谢阅读~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89679.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89679.shtml
英文地址,请注明出处:http://en.pswp.cn/web/89679.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Camera相机人脸识别系列专题分析之十七:人脸特征检测FFD算法之libhci_face_camera_api.so 296点位人脸识别检测流程详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: Camera相机人脸识别系列专题分析之十七:人脸特征检测FFD算法之libhci_face_camera_api.so 296点位人脸识别检测流程详解 目录 一、背景 二、:FFD算法libhci_face_camera_api.s…

PostgreSQL 16 Administration Cookbook 读书笔记:第7章 Database Administration

编写一个要么完全成功要么完全失败的脚本 事务&#xff08;transaction&#xff09;可以实现all or nothing。不过这里指的是psql的-和--single-transaction选项。可以实现transaction wrapper&#xff1a; 此选项只能与一个或多个 -c 和/或 -f 选项组合使用。它会导致 psql 在…

DeepSeekMath:突破开源语言模型在数学推理中的极限

温馨提示&#xff1a; 本篇文章已同步至"AI专题精讲" DeepSeekMath&#xff1a;突破开源语言模型在数学推理中的极限 摘要 数学推理由于其复杂且结构化的特性&#xff0c;对语言模型构成了重大挑战。本文介绍了 DeepSeekMath 7B&#xff0c;该模型在 DeepSeek-Code…

实体类序列化报错:Caused by: java.lang.NoSuchMethodException: com.xx.PoJo$Item.<init>()

原实体类代码EqualsAndHashCode(callSuper true) Data public class Pojo extends BaseBean {private static final long serialVersionUID -4291335073882689552L;ApiModelProperty("")private Integer id;......private List<Item> list;AllArgsConstructo…

基于单片机病床呼叫系统/床位呼叫系统

传送门 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目速选一览表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目功能速览 概述 该系统是以单片机STM32F103为核心的基于无线网络的医院病房呼叫系统&#xff0c;分为从机和主机两…

[黑马头条]-登录实现思路

需求分析在黑马头条项目中&#xff0c;登录有两种方式&#xff1a;一种是用户输入账号密码后登录&#xff0c;这种方式登陆后的权限很大&#xff0c;可以查看&#xff0c;也可以进行其他操作&#xff1b;另一种方式就是用户点击不登录&#xff0c;以游客的身份进入系统&#xf…

了解.NET Core状态管理:优化技巧与常见问题解决方案

前言 欢迎关注dotnet研习社&#xff0c;今天我们聊聊“ .NET Core 中的状态管理”。 在Web应用程序中&#xff0c;管理和维持状态是一个非常重要的主题&#xff0c;尤其是在无状态的环境中&#xff0c;如 HTTP 协议和 RESTful API。对于基于 .NET Core 构建的应用程序&#xff…

504网关超时可能是哪些原因导致?

在网络访问中&#xff0c;504 网关超时&#xff08;Gateway Timeout&#xff09;如同一个突然亮起的警示灯&#xff0c;打断用户的浏览或操作流程。这个 HTTP 状态码意味着服务器作为网关或代理时&#xff0c;未能在规定时间内收到上游服务器的响应。引发504错误的核心因素有哪…

ComfyUI 常见报错问题解决方案合集(持续更新ing)

前言&#xff1a; 本文汇总了 5 大高频问题 及其解决方案&#xff0c;涵盖&#xff1a; HuggingFace 认证修复&#xff08;Token 申请 手动下载指南&#xff09; ComfyUI 版本更新&#xff08;完整命令 依赖管理&#xff09; 自启动配置&#xff08;Conda 环境 权限修复&…

完美解决Linux服务器tomcat开机自启动问题

经过多次测试终于彻底解决tomcat开机自启动的问题了 PID3ps aux | grep /home/server/shichuan/ | grep java | awk {print $2} if [ -n "$PID3" ]; then 这个判断pid的方式还是可能出现启动失败的情况 # tail -n 1 /home/server/shichuan/logs/catalina.out |grep…

kotlin部分常用特性总结

<h3>Kotlin中类和对象初始化</h3><ul> <li>添加open关键字代表可以被继承</li> <li>Any 是所有类的父类,类似Object,包含 equals() hashCode() toString()方法</li> <li>constructor 关键字代表构造函数, constructor关键字可…

PHP 就业核心技能速查手册

# PHP 就业核心技能速查手册 > 高效聚焦市场所需&#xff0c;快速提升竞争力 --- ## 一、语法基础&#xff08;必会&#xff01;&#xff09; php // 1. 变量与数据类型 $price 19.99; // 浮点型 $isStock true; // 布尔型 // 2. 流程控制 foreach ($…

从混沌到秩序:数据科学的热力学第二定律破局——线性回归的熵减模型 × 最小二乘的能量最小化 × 梯度下降的负反馈控制系统,用物理定律重构智能算法的统一场论

目录 一、机器学习是什么&#xff1f; 1.1 什么是机器学习&#xff1f; 1.2 机器学习的三大类型 二、线性回归是什么&#xff1f; 2.1 通俗理解 2.2 数学表达 三、最小二乘法&#xff08;Least Squares Method&#xff09; 3.1 什么是损失函数&#xff1f; 3.2 什么是最小…

BI 数据可视化平台建设(3)—首页性能提升实践

作者&#xff1a; vivo 互联网大数据团队- Wang Lei 本文是vivo互联网大数据团队《BI 数据可视化平台建设》系列文章第3篇。 随着越来越多代码的堆积&#xff0c;平台的运行加载性能也在逐步下降&#xff0c;在不同程度上极大地影响了用户体验&#xff0c;从而导致用户流失。本…

基于Python的毕业设计选题管理系统设计与实现

基于Python的毕业设计选题管理系统设计与实现摘要本论文详细阐述了一个基于Python的毕业设计选题管理系统的设计与实现过程。该系统采用了Python的Tkinter库构建图形用户界面&#xff0c;使用SQLite数据库存储数据&#xff0c;实现了高校毕业设计选题过程中的教师出题、学生选题…

如何在HTML5页面中嵌入视频

在HTML5中嵌入视频主要使用<video>标签&#xff0c;这是一种简单且标准的方式。以下是详细步骤和示例&#xff1a; 基础实现 <!DOCTYPE html> <html> <head><title>视频嵌入示例</title> </head> <body><!-- 基础视频播放器…

java操作Excel两种方式EasyExcel 和POI

一、POI1.引入依赖<!-- 03 xls--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version> </dependency><!-- 07 xlsx --> <dependency><groupId>org.a…

Openlayers 面试题及答案180道(141-160)

《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面试题-专栏总目录 文章目录 一、本文面试题目录 141. 如何在生产环境中优…

LangChain面试内容整理-知识点24:实战案例:智能助手 Agent 构建

本案例讲述如何用LangChain构建一个结合多个工具的智能助手 Agent。智能助手需要理解用户复杂请求,通过调用不同工具(如搜索、计算、查数据库等)执行多步推理,再给出答案。LangChain的Agent框架非常适合这种场景。 构建步骤: 确定需求和选择Agent类型:假设我们要一个能上…

【MATLAB例程】Taylor算法用于TOA(到达时间)的三维标签位置解算,可自适应基站数量。附下载链接

本文给出自适应锚点&#xff08;基站&#xff09;的Taylor算法解算TOA&#xff08;到达时间&#xff09;的MATLAB代码。参考论文&#xff1a;《基于Taylor-Chan算法的改进UWB室内三维定位方法》中的Taylor算法来解算TOA的复现程序&#xff08;MATLAB&#xff09;。 文章目录运行…