红黑树的概念和模拟实现[C++]
文章目录
- 红黑树的概念
- 一、红黑树的性质
- 红黑树原理
- 二、红黑树的优势和比较
- 红黑树的模拟实现
- 构建红黑树的数据结构定义节点的基本结构和初始化方式
- 插入新节点
- 插入新节点的颜色
- 调整颜色和结构以满足红黑树性质
- 红黑树的应用场景
红黑树的概念
一、红黑树的性质
红黑树是一种自平衡的二叉搜索树。它的节点被标记为红色或黑色,通过特定的规则来保持树的近似平衡(最长路径不超过最短路径的二倍)。其主要规则:
- 每个节点要么是红色,要么是黑色。
- 根节点是黑色的。
- 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。[每条路径的黑色节点的数量是相等的]
- 如果一个节点是红色的,那么它的两个子节点都是黑色的。[也就是一条路径中,没有连续的红色节点]
- 每个叶子节点(NIL 节点)是黑色的。[如图中所示,就是将所有空节点当作是黑色节点,不是很重要]
注:在数路径的时候要以空节点为结束去数路径,如图有11条路经
红黑树原理
那么红黑树是如何凭借颜色来控制平衡的呢?
我们想在不违反红黑树规则,极端情况如下图【注:这种情况不一定出现,用来方便 理解】
最短的路径:全是黑色 最长的路径:一黑一红
那么我们设最短路径为n,最长路径也就是2n,即这张图中最长路径就是最短路径的2倍。
而还可以是这种情况如下图
这种情况就是最短路径的2倍大于最长路径。
所以这就是红黑树的近似平衡(即最长路径不超过最短路径的二倍)
而我们这里的最长最短路径是在红黑树规则理论上而言,实际的红黑 树中最长最短不要低估是上米娜的图所示。
二、红黑树的优势和比较
红黑树之所以在众多数据结构中脱颖而出,是因为它在插入和删除操作时能够在 O(log n)
的时间复杂度内自动调整,保持平衡,从而保证了高效的查找、插入和删除性能。
以AVL树做对比:
平衡机制:
- AVL 树通过严格的平衡条件(左右子树的高度差绝对值不超过 1)来保持平衡。每次插入或删除操作后,如果导致树不平衡,需要进行复杂的旋转操作来重新平衡树。
- 红黑树的平衡条件相对宽松,通过节点颜色的约束(红黑规则)来保持大致平衡。插入或删除操作后,调整平衡的操作相对较简单。
性能:
- 在频繁插入和删除操作的情况下,红黑树的性能通常优于 AVL 树。因为 AVL 树的平衡调整更为频繁且复杂,可能导致更多的开销。
- 对于查找操作,AVL 树由于其更严格的平衡特性,可能会稍微快一些。
空间复杂度:
- 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){}
};
先定义一个枚举类型 Color
和一个模板结构体 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
,并将指针_left
、_right
和_parent
初始化为nullptr
。
插入新节点
插入新节点的颜色
首先,按照二叉搜索树的插入规则,将新节点插入到合适的位置。
新插入的节点默认是红色,原因:
如果我们插入红色节点我们破坏规则4(如果一个节点是红色的,那么它的两个子节点都是黑色的,也就是一条路径中,没有连续的红色节点)
如果我们插入黑色节点我们破坏规则3(从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点)
那么我们插入黑色节点的时候规则3必然会被破坏,而插入红色节点如果父节点是黑色则没有事情,如果父节点是红色才会破坏规则4==,所以相比之下插入红色节点更好。
调整颜色和结构以满足红黑树性质
- 如果插入节点的
父节点是黑色
,那么无需做任何调整,树已经满足红黑树的性质。- 如果插入节点的
父节点是红色
,那么会出现违反红黑树性质的情况,需要进行调整。- 情况一:父节点的
兄弟节点是黑色
,且父节点是祖父节点的左孩子
- 情况 1.1:插入节点是父节点的右孩子
对父节点进行左旋,将当前情况转换为情况 1.2。 - 情况 1.2:插入节点是父节点的左孩子
将父节点染成黑色,祖父节点染成红色,对祖父节点进行右旋。
- 情况 1.1:插入节点是父节点的右孩子
- 情况二:父节点的
兄弟节点是黑色
,且父节点是祖父节点的右孩子
- 情况 2.1:插入节点是父节点的左孩子
对父节点进行右旋,将当前情况转换为情况 2.2。 - 情况 2.2:插入节点是父节点的右孩子
将父节点染成黑色,祖父节点染成红色,对祖父节点进行左旋。
- 情况 2.1:插入节点是父节点的左孩子
- 情况三:父节点的
兄弟节点是红色
将父节点和兄弟节点染成黑色,祖父节点染成红色,以祖父节点为新的插入节点继续调整。
- 情况一:父节点的
- 如果插入节点的
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){//如果u存在,cur和parent都是红,grandfather是黑//p,u变成黑,g变成红,g当成cur向上调整//u存在且是红 -> 变色进行调整Node* grandfather = parent->_parent;//p在g的左边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{//u存在且为黑或者不存在 -> 旋转加变色if (cur == parent->_left){//单旋// g// p u//cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//双旋// g// p u// cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{//u在g的左边// g// u pNode* uncle = grandfather->_left;//u存在且为红 -> 直接变色if (uncle&&uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{//u存在且为黑或者不存在 -> 旋转加变色if (cur == parent->_right){//单旋// g// u p// cRotateL(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;}
红黑树的应用场景
红黑树在许多领域都有广泛的应用,比如:
数据库中的索引结构。
各种编程语言的标准库中,如 Java 中的 TreeMap 和 TreeSet 。
总之,红黑树作为一种高效且强大的数据结构,对于优化程序性能和提高数据管理效率具有重要意义。深入理解和掌握红黑树,将为我们在计算机科学领域的探索提供有力的支持。
相关文章:

红黑树的概念和模拟实现[C++]
文章目录 红黑树的概念一、红黑树的性质红黑树原理二、红黑树的优势和比较 红黑树的模拟实现构建红黑树的数据结构定义节点的基本结构和初始化方式插入新节点插入新节点的颜色调整颜色和结构以满足红黑树性质 红黑树的应用场景 红黑树的概念 一、红黑树的性质 红黑树是一种自平…...

网络安全应急响应概述
前言 在网络安全领域,有一句广为人知的话:“没有绝对的安全”。这意味着任何系统都有可能被攻破。安全攻击的发生并不可怕,可怕的是从头到尾都毫无察觉。当系统遭遇攻击时,企业的安全人员需要立即进行应急响应,以将影响…...

【C++】链表操作技巧综合:重排链表(带你理顺链表的做题思路)
1.题目 2.算法思路 这是一道关于链表的综合题,一共涉及到三个步骤,其中每个步骤单拎出来就可以当一道单独的题目。所以需要大家对链表的操作十分熟悉,否则可能需要大量的时间做这道题目,而且还要很多的bug。 第一个步骤…...

行为型设计模式2:观察者/职责链/中介者/访问者
设计模式:观察者/职责链/中介者/访问者 (qq.com)...

叛逆,批判
1、对以往说法的批判之一(第一次这么公开批判是2004-2005年): 这部英文版的《数学百科全书》似乎是从俄语版翻译过来的?我查了三本引用的图书文献,都没有关于“nonsingular”和“singular”的类似下面的说法ÿ…...

Linux 命令,mkdir说明与使用
1:mkdir命令功用: 用于创建一个或多个目录,创建目录,必须在父目录中写上权限。 新目录的默认模式为0777,可以由系统或用的umask来修改。 2:命令构件: mkdir [options] directories 3:参数选项: -m&#x…...

24. 两两交换链表中的节点(Java)
目录 题目描述:示例 :代码实现: 题目描述: 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换&am…...

linux虚拟机设置固定ip
修改/etc/sysconfig/network-scripts目录下ifcfg-eth0文件,各虚拟机这个文件名不一致,ifcfg-XX格式 vim /etc/sysconfig/network-scripts/ifcfg-eth0BOOTPROTO设置为static,然后在最后添加固定IP地址和默认网关、DNS等配置,IP地址…...

mysql问题解决
1.etl数据同步时,发现连接不上要同步的数据库 解决方法:关闭mysql的ssl,步骤如下: 在MySQL中禁用SSL连接涉及修改服务器的配置文件(通常是my.cnf或my.ini,取决于你的操作系统和MySQL版本)。以…...

类和对象(下)C++
1.初始化列表 1.为什么有初始化列表,它的作用? ->初始化列表,是构造函数初始化的另一种形式。 ->在语法上面理解,初始化列表可以认定为是每个成员变量定义初始化的地方. ->引用成员变量,const成员变量&am…...

常用在线 Webshell 查杀工具推荐
一、简介 这篇文章将介绍几款常用的在线 Webshell 查杀工具,包括长亭牧云、微步在线云沙箱、河马和VirusTotal。每个工具都有其独特的特点和优势,用于帮助用户有效检测和清除各类恶意 Webshell,保障网站和服务器的安全。文章将深入探讨它们的…...

RPC远程调用框架Dubbo
一、分布式服务调用_什么是RPC RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务。 大白话理解就是:RPC让你用别人家的东西就像自己家的一样。 RPC两个作用: 屏蔽远程调用跟本地调用的区别,…...

基于STM32的智能灌溉系统
目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码传感器读取和控制代码应用场景 农业灌溉花园自动灌溉常见问题及解决方案 常见问题解决方案结论 1. 引言 智能灌溉系统通过实时监测土壤湿度和环境温度,自动控制灌溉设…...

Datawhale AI 夏令营 Task3(半成品,仍在学习理解
课程链接 / 知识点整理 (一)...

细腻呵护静音生活缓冲器,家具中的隐形侍者
在忙碌的生活节奏中,家是我们寻找宁静与放松的避风港。而家具缓冲器,就像一位隐形的侍者,在不经意间为我们营造出温馨、宁静的居住环境。它们静静地工作,细腻地呵护着每一处细节,让家的每一次触碰成为一次尊享体验。 细…...

【MATLAB源码-第243期】基于simulink的CUK斩波电路仿真,输出各节点波形。
操作环境: MATLAB 2022a 1、算法描述 CUK电路是一种高效的直流-直流转换器,它以其独特的能量传递方式和高效的电压转换能力,在许多电力电子应用中得到了广泛的使用。下面将详细描述CUK电路的工作原理、各个组成部分以及其在实际应用中的优…...

springboot项目不能同时跑junit4和junit5的解决方法
springboot项目的maven test只会跑junit4 RunWith注解的测试类,而不会跑junit5 ExtendWith的测试类 解决方法:pom加上以下plugin,版本号需要3.0.0-M5及以上 <plugin><groupId>org.apache.maven.plugins</groupId><art…...

【IO】使用消息队列完成两个进程之间相互通信
目录 1、使用消息队列完成两个进程之间相互通信 2、共享内存实现两个进程之间的通信 3、思维导图 1、使用消息队列完成两个进程之间相互通信 //msgsnd.c #include <myhead.h>// 要发送的消息类型 struct msgbuf {long mtype;char mtext[1024]; };// 定义一个宏&#…...

Web开发:用C#的逻辑理解VUE语法(VUE + Webapi小白开发笔记)
适用阅读对象:需要兼顾前端的C#后端开发人员(基础笔记) 目录 一、后端交互-获取实体数据 二、变量 1.声明 2.作用域 三、字符串的处理 四、数组(列表)的处理 1.数组中的SELECT语法(提取特定字段到新数组) 2.数…...

操作系统文件位置指针
文件位置指针 与标准IO的文件读写位置指针一样,系统IO时也会有一个表示位置的指针在移动,会随着读写操作的执行向后自动移动 当需要随机位置进行读写操作时,那么需要移动位置指针的位置 off_t lseek(int fd, off_t offset, int whence); 功…...

设计模式的概念
设计模式主要分为三类:创建类的设计模式、结构型设计模式、行为型设计模式。 创建类的设计模式:简单工厂,工厂模式,抽象工厂,建造者,单例,原型 结构型设计模式:代理模式、享元模式 行…...

VMware17下载与安装
1.下载 通过百度网盘分享的文件:VMware17 链接:https://pan.baidu.com/s/1gCine3d3Rp_l3NYAu5-ojg 提取码:ek25 --来自百度网盘超级会员V3的分享 2.安装...

mv命令学习
移动和重命名文件 mv mv命令的作用就是将文件系统的文件从一个地方移动到另一个地方。 $ pwd /home/scott/libby $ ls libby_arrowrock.jpg libby_bak.jpg libby.jpg ➥libby_on_couch.jpg on_floor $ ls ~/pictures/dogs libby_on_floor_01.jpg libby_on_floor_03.jpg li…...

西北航天基地采用Infortrend NAS存储做影视后期及共享
用户背景: 创建最早的综合型航空航天基地,占地5万平方米,每年约300天进行航天试验 挑战: 西北航天基地规模大任务多,分别有不同的项目组负责试验,项目组需要获取试验任务影像资料,用于分析总…...

GitHub每日最火火火项目(8.6)
项目名称:bghira / SimpleTuner 项目介绍:SimpleTuner是一个通用的微调工具包,主要面向Stable Diffusion 2.1、Stable Diffusion 3、DeepFloyd和SDXL等模型。它旨在为这些模型提供一种方便的方式进行微调,以适应不同的应用场景和需…...

LangChain与CI/CD的无缝对接:自动化部署的新前沿
LangChain与CI/CD的无缝对接:自动化部署的新前沿 在当今快速发展的软件开发领域,持续集成/持续部署(CI/CD)已成为提升开发效率和软件质量的关键实践。LangChain,作为一个假设的编程辅助工具,如果存在&…...

Laravel为什么会成为最优雅的PHP框架?
目录 1. 设计哲学 1.1 表达性语法 1.2 约定优于配置 1.3 优雅的异常处理 2. 核心特性 2.1 Eloquent ORM 2.2 路由系统 2.3 Blade模板引擎 2.4 Artisan命令行工具 3. 社区支持 3.1 丰富的文档和教程 3.2 Packalyst:丰富的扩展包 3.3 社区活动和会议 4.…...

LabVIEW中的Reverse String函数与字节序转换
在LabVIEW中,数据的字节序(也称为端序)问题通常出现在数据传输和存储过程中。字节序可以分为大端(Big-Endian)和小端(Little-Endian),它们分别表示高字节存储在低地址和低字节存储在…...

用OpenCV与MFC写一个简单易用的图像处理程序
工厂里做SOP及测试报告以及员工资格鉴定等常需用到简单的图像处理,PS等软件正版费用不菲,学习起来成本也高。Windows自带的图像处理软件,用起来也不是那么得心应手。因此我用OpenCV与MFC写了一个简单易用的图像处理程序。 程序界面 基于简单…...

go语言的actor框架和air工具有什么区别?
Go语言的Actor框架和Air工具在多个方面存在显著的区别,主要体现在它们的设计目的、功能特性以及应用场景上。 ### Go语言的Actor框架 **设计目的与功能特性**: * **设计目的**:Actor框架是专为高并发和分布式系统设计的编程模型。它通过将系统…...