红黑树剖析

目录

一.   红黑树的概念

 二.   红黑树的性质

三.   红黑树节点的定义

四.   红黑树的插入操作

 4.1        uncle存在且颜色为红

4.2        uncle不存在或者uncle存在且为黑

五.   整体代码展示


一.   红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路 径会比其他路径长出俩倍,因而是接近平衡的

 

 二.   红黑树的性质

(1)每个节点是黑色和红色中的一种

(2)根节点是黑色的

(3)红节点的子节点必须是黑节点(不能出现两个连续的红节点

(4)对于一个节点,左子树内的黑色节点数目等于右子树内黑色节点数目

        那我们来想想,为什么之前概念说没有一条路径会超过其他路径的两倍(即最长路径中节点个数不会超过最短路径节点个数的两倍)?

因为我们可以看见最短的路径是这条路径上所有节点都为黑色节点的时候:

而最长路径就是一黑一红依次排列的时候:

可以看见最长路径最大就为最短路径的两倍,所以最长路径是不会超过最短路径的两倍的。 

三.   红黑树节点的定义

enum Colour
{RED,BLACK
};
template<class K,class V>
struct RBTreeNode
{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Colour _col;RBTreeNode(const pair<K,V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_col(RED){}
};

我们可以看见,创建新节点时,我们默认给的颜色是红色,为什么呢?

那是因为如果我们给的是黑色,就会导致左右子树的黑色节点数目不相等,与红黑树的性质相违背。

四.   红黑树的插入操作

由于红黑树除了插入操作以外,其余操作与搜索二叉树类似,所以这里讲插入操作。

那我们插入红色节点之后,是否对树的结构造成了破坏呢?

可以看见,如果父亲节点是黑色的,那实际上是不会破坏结构的,而如果父亲节点是红色,就违背了性质三(不能有连续的两个红色节点),这时候就要调节树的结构

 父亲节点为红色时,就要调节树的结构,我们先对节点起个名字

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

 4.1        uncle存在且颜色为红

代码展示(由于parent和uncle是grandparent的左还是右不影响结果,所以这里让parent为左,uncle为右):

Node* grandparent = parent->_parent;
Node* uncle = nullptr;
if (uncle && uncle->_col == RED)
{parent->_col = BLACK;uncle->_col = BLACK;grandparent->_col = RED;if (grandparent == _root){grandparent->_col = BLACK;}else{cur = grandparent;parent = cur->_parent;//迭代上去}
}

总结:当uncle存在且为红时,我们需要把parent和uncle变为黑色grandparent变为红色,如果grandparent为根节点,则再次把他的颜色变为黑色,如果不是,则令cur=grandparent,迭代上去直到根节点。 

4.2        uncle不存在或者uncle存在且为黑

代码展示(同上parent为左,uncle为右,这里要分cur是parent的左还是右): 

else
{//		g//	p		u//cif (cur == parent->_left){RotaleR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//		g//	p		u//		celse{RotaleL(parent);RotaleR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;
}void RotaleL(Node* parent)
{rotalSize++;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;subR->_left = parent;if (subRL){subRL->_parent = parent;}Node* ppnode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = subR;}else if (parent == ppnode->_right){ppnode->_right = subR;}subR->_parent = ppnode;}
}
void RotaleR(Node* parent)
{rotalSize++;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;subL->_right = parent;if (subLR){subLR->_parent = parent;}Node* ppnode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subL;}else if (ppnode->_right == parent){ppnode->_right = subL;}subL->_parent = ppnode;}
}

总结:对于cur是parent左节点的情况,需要将这棵树在grandparent右旋,并将grandparent的颜色变为红色,parent的颜色变为黑色;对于cur是parent右节点的情况,单一的旋转不能满足条件了,此时需要先将这棵树在parent左旋,再在grandparent处右旋,并将grandparent的颜色变为红色cur的颜色变为黑色

五.   整体代码展示

enum Colour
{RED,BLACK
};
template<class K,class V>
struct RBTreeNode
{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Colour _col;RBTreeNode(const pair<K,V>& 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* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandparent = parent->_parent;Node* uncle = nullptr;//parent和uncle是grandparent的左还是右不影响结果//cur是parent的左还是右不影响结果if (parent == grandparent->_left){uncle = grandparent->_right;//uncle存在且为红if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandparent->_col = RED;if (grandparent == _root){grandparent->_col = BLACK;}else{cur = grandparent;parent = cur->_parent;}}else{//		g//	p		u//cif (cur == parent->_left){RotaleR(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//		g//	p		u//		celse{RotaleL(parent);RotaleR(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}else{uncle = grandparent->_left;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandparent->_col = RED;if (grandparent == _root){grandparent->_col = BLACK;}else{cur = grandparent;parent = cur->_parent;}}else{//		g//	u		p//				cif (cur == parent->_right){RotaleL(grandparent);parent->_col = BLACK;grandparent->_col = RED;}//		g//	u		p//		celse{RotaleR(parent);RotaleL(grandparent);cur->_col = BLACK;grandparent->_col = RED;}break;}}}return true;}void RotaleL(Node* parent){rotalSize++;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;subR->_left = parent;if (subRL){subRL->_parent = parent;}Node* ppnode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = subR;}else if (parent == ppnode->_right){ppnode->_right = subR;}subR->_parent = ppnode;}}void RotaleR(Node* parent){rotalSize++;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;subL->_right = parent;if (subLR){subLR->_parent = parent;}Node* ppnode = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;subL->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = subL;}else if (ppnode->_right == parent){ppnode->_right = subL;}subL->_parent = ppnode;}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);}bool _check(Node* root,int blackNum,int refBlackNum){if (root == nullptr){if (blackNum != refBlackNum){cout <<"黑色节点数目不同" << endl;return false;}//cout << blackNum << endl;return true;}else 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,refBlackNum) && _check(root->_right, blackNum,refBlackNum);}bool IsBalance(){if (_root && _root->_col == RED){return false;}int refBlackNum = 0;Node* cur = _root;while (cur){if(cur->_col==BLACK)refBlackNum++;cur = cur->_left;}return _check(_root,0,refBlackNum);}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 NULL;}
private:Node* _root=nullptr;size_t rotalSize=0;
};

 总结

好了,到这里今天的知识就讲完了,大家有错误一点要在评论指出,我怕我一人搁这瞎bb,没人告诉我错误就寄了。

祝大家越来越好,不用关注我(疯狂暗示)

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

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

相关文章

OpenCV 4.9基本绘图

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV使用通用内部函数对代码进行矢量化 下一篇&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; ​目标 在本教程中&#xff0c;您将学习如何&am…

广东小团队惊艳业绩揭秘:链动模式助力面膜销售破千万!

惊爆&#xff01;广东一个默默无闻的小团队竟然在短短一个月内&#xff0c;仅凭销售面膜就实现了超过千万的惊人业绩&#xff01;这背后究竟隐藏着怎样的秘密武器呢&#xff1f; 揭开链动模式的神秘面纱 链动模式&#xff0c;作为社交电商领域的一股新兴力量&#xff0c;正以其…

【强化学习的数学原理-赵世钰】课程笔记(一)基本概念

目录 一. 内容概述1. 通过案例介绍强化学习中的基本概念2. 在马尔可夫决策过程&#xff08;MDP&#xff09;的框架下将概念正式描述出来 二. 通过案例介绍强化学习中的基本概念1. 网格世界&#xff08;A grid world example&#xff09;2. 状态&#xff08;State&#xff09;3.…

Spring AOP + 自定义注解 实现公共字段的填充

Spring AOP 自定义注解 实现公共字段的填充 代码冗,不利于后期维护. 定义操作这些字段的方法类型 实现步骤&#xff1a; 自定义注解AutoFill,用于表示操作这些公共字段的方法自定义切面类AutoFillAspect,统一拦截&#xff0c;通过反射获取方法入参&#xff0c;并填充公共字段…

【THM】Burp Suite:Other Modules(其他模块)-初级渗透测试

介绍 除了广泛认可的Repeater和Intruder房间之外,Burp Suite 还包含几个鲜为人知的模块。这些将成为这个房间探索的重点。 重点将放在解码器、比较器、排序器和组织器工具上。它们促进了编码文本的操作,支持数据集的比较,允许分析捕获的令牌内的随机性,并帮助您存储和注释…

9、鸿蒙学习-开发及引用静态共享包(API 9)

HAR&#xff08;Harmony Archive&#xff09;是静态共享包&#xff0c;可以包含代码、C库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。HAR不同于HAP&#xff0c;不能独立安装运行在设备上&#xff0c;只能作为应用模块的依赖项被引用。…

MongoDB 6.1 及以上版本使用配置文件的方式启动报错 Unrecognized option: storage.journal.enabled

如果你使用的 MongoDB 的版本大于等于 6.1&#xff0c;并且在 MongoDB 的配置文件中编写了如下内容 storage:journal:# 启用或禁用持久性日志以确保数据文件保持有效和可恢复# true 启用&#xff1b;false 不启用# 64 位系统默认启用&#xff0c;启用后 MongoDB 可以在宕机后根…

Linux多进程通信(1)——无名管道及有名管道使用例程

管道是半双工通信&#xff0c;如果需要 双向通信&#xff0c;则需要建立两个管道&#xff0c; 无名管道&#xff1a;只能父子进程间通信&#xff0c;且是非永久性管道通信结构&#xff0c;当它访问的进程全部终止时&#xff0c;管道也随之被撤销 有名管道&#xff1a;进程间不需…

RK3568驱动指南|第十四篇 单总线-第162章DS18B20驱动读时序编写

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

Golang 开发实战day06 - Boolean Conditional

Golang 教程06 - Boolean & Conditional 1. Boolean & Conditional 1.1 什么是布尔类型&#xff1f; 想象一下&#xff0c;你正在玩一个古老的游戏&#xff0c;只有两个选项&#xff1a;是或否。在 Golang 中&#xff0c;这就是布尔类型&#xff0c;用 bool 关键字表…

【Linux实验室】DNS域名解析服务——超详细实验操作!

DNS域名解析 DNS域名解析服务——超详细实验操作&#xff01;&#xff01;&#xff01;序言DNS 基本概述分布式、层次数据库DNS 层次结构DNS 查询步骤DNS 查询类型DNS服务器类型DNS 缓存反向 DNS 查询如何检查 DNS 记录是否生效 Bind解析服务Bind简介bind的服务类型 DNS域名解析…

深入解析实时数仓Doris:Rollup上卷表与查询

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 一、基本概念二、Aggregate 和 Unique 模型中的 ROLLUP三、Duplicate 模型中的 ROLLUP四、ROLLUP 调整前缀索引五、ROLLUP使…

【深耕 Python】Data Science with Python 数据科学(7)书352页练习题

写在前面 关于数据科学环境的建立&#xff0c;可以参考我的博客&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;1&#xff09;环境搭建 往期数据科学博文&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;2&#xf…

每日面经分享(pytest测试案例,接口断言,多并发断言)

pytest对用户登录接口进行自动化脚本设计 a. 创建一个名为"test_login.py"的测试文件&#xff0c;编写以下测试脚本 import pytest import requests# 测试用例1&#xff1a;验证登录成功的情况 # 第一个测试用例验证登录成功的情况&#xff0c;发送有效的用户名和密…

iOS系统文件备份与还原:保护和管理手机中的关键数据

​ 目录 引言 用户登录工具和连接设备 查看设备信息&#xff0c;电池信息 查看硬盘信息 硬件信息 查看 基带信息 销售信息 电脑可对手机应用程序批量操作 运行APP和查看APP日志 IPA包安装测试 注意事项 引言 苹果手机与安卓手机不同&#xff0c;无法直接访问系统文件…

Chatgpt掘金之旅—有爱AI商业实战篇|文案写作|(三)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、前言 人工智能&#xff08;AI&#xff09;技术作为当今科技创新的前沿领域&#xff0c;为创业者提供了广阔的机会和挑战。随着AI技术的快速发展和应用领域的不断拓展&…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

Linux和Windows安装PHP依赖管理工具Composer

Composer 是 PHP 的一个依赖管理工具。它允许申明项目所依赖的代码库&#xff0c;会在项目中安装它们。 Composer 不是一个包管理器。是的&#xff0c;它涉及 "packages" 和 "libraries"&#xff0c;但它在每个项目的基础上进行管理&#xff0c;在你项目的…

【Springboot整合系列】SpringBoot整合WebService

目录 Web服务介绍Web服务的两种类型Web服务架构Web服务的主要特点Web服务使用场景Web服务标准和技术 WebService介绍WebService的作用适用场景不适用场景 WebService的原理三个角色相关概念 WebService开发框架代码实现服务端1.引入依赖2.实体类3.业务层接口接口实现类 4.配置类…

python对接百度云车牌识别

注册百度智能云&#xff0c;选择产品服务。 https://console.bce.baidu.com/ 每天赠送200次&#xff0c;做开发测试足够了。 在应用列表复制 AppID , API Key ,Secret Key 备用。 SDK下载地址 https://ai.baidu.com/sdk#ocr 下载SDK文件&#xff0c;解压&#xff0c;…