c++红黑树的模拟实现

目录

1. 红黑树的概念

​编辑

 2. 红黑树的性质

3. 红黑树的模拟实现 

 3.1 红黑树节点的定义

3.2 红黑树的插入

旋转代码 

插入主逻辑代码 

验证是否平衡 

4. 红黑树与AVL树的比较 


1. 红黑树的概念

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

那么红黑树是凭什么满足没有最长路径不超过最短路径的两倍呢?我们去看看他的性质! 

 2. 红黑树的性质

1. 每个结点不是红色就是黑色
2. 根节点是黑色的(根节点必须为黑)
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的(没有连续的红色节点)
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点

(每条路径上的黑色节点都相同)
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)(注意这里的叶子是空结点,我们学习的时候不会对他有过多的理睬)

难道凭借这几个性质就能得出最长路径不超过最短路径的两倍吗?

是的没错!这些性质足以!

红色节点的孩子必然是黑色,每条路径的黑色节点个数都相同。这不就固定了最短路径必然是全黑的,最长路径必然是一黑一红,同时每条路径的黑色节点个数相同,那么最长路径就是两倍的最短路径。

3. 红黑树的模拟实现 

 3.1 红黑树节点的定义

enum Color
{RED,BLACK
};template<class K,class V>
class RBTreeNode
{
public:RBTreeNode(const pair<K, V>& kv,const Color& color=RED)//颜色的缺省参数给定为红色:_kv(kv), _color(color),_left(nullptr),_right(nullptr),_parent(nullptr)
private:pair<K, V> _kv;Color _color;RBTreeNode<K, V> _left;RBTreeNode<K, V> _right;RBTreeNode<K, V> _parent;
};

其他的我们都能理解,但是颜色的缺省参数为什么给定红色呢?

我们想一想,根据红黑树的几条性质,我们插入的时候要怎么检测呢?难道每插入一个都检查一下树的每条路径黑色节点个数是否相同吗?

当然不是,插入时我们只需要检测是否有连续的红色节点。

当我们插入的是红色节点,其父亲为黑就正常,其父亲为红就进行处理。

但如果我们插入的是黑色,那么永远满足没有连续的红色节点,也触发不了处理过程。 

3.2 红黑树的插入

红黑树的插入规则仍是延续二叉搜索树的规则,在插入后依据红黑树的规则对树进行调整。 

我们来看看吧。

当插入节点后需要检测是否满足红黑树的特性。

新插入的节点为红色,如果他的父亲是黑色,满足红黑树特性,over;

如果他的父亲是红色,违反了红黑树的特性,这时就需要进行处理。

这个时候需要分情况讨论。我们约定c为插入节点,p为其父亲,u为其叔叔,g为其爷爷。这几个节点都是今天的主角。第一主角则是叔叔节点u,这是为什么呢?

叔叔节点的状态决定了我们的操作。

可以看到,关键就在于叔叔节点的状态。

我们来画图看看

u存在且为红

u不存在且为黑

当p为g左且c为p左 

当p为g右且c为p右

当p为g右且c为p左时

 当p为g左且c为g右时

以上就是红黑树的插入思路了。我们来写一写代码吧。

旋转代码 

旋转思路与AVL树没有差别,只是需要将对平衡因子的调节改为对颜色的调节。

void RotateL(Node* parent)//左单旋
{//记录会进行迁移的节点Node* cur = parent->_right;//cur节点Node* CL = cur->_left;//cur的左孩子parent->_right = CL;//cur->_left变成parent->_rightif (CL)//如果CL存在,更新其父亲,以免触发空指针的解引用CL->_parent = parent;cur->_left = parent;//parent给cur->_leftNode* grandfather = parent->_parent;//先记录parent的父亲parent->_parent = cur;//更新parent的父亲if (parent == _root)//parent为根,将cur置为_root,其父亲为空{_root = cur;}else//不为根,更新其父亲{if (parent == grandfather->_left)grandfather->_left = cur;elsegrandfather->_right = cur;}cur->_parent = grandfather;}
void RotateR(Node* parent)//右单旋
{//记录会进行迁移的节点Node* cur = parent->_left;Node* CR = cur->_right;parent->_left = CR;if (CR)CR->_parent = parent;cur->_right = parent;Node* grandfather = parent->_parent;//记录parent的父亲parent->_parent = cur;if (parent == _root)//parent为根{_root = cur;cur->_parent = nullptr;}else//不为根{if (parent == grandfather->_left)//判断parent的位置grandfather->_left = cur;elsegrandfather->_right = cur;}cur->_parent = grandfather;}
插入主逻辑代码 
bool insert(const pair<K, V>& kv)
{if (_root == nullptr)_root = new Node(kv,BLACK);else//插入{Node* cur = _root, * parent = nullptr;//虽然是三叉链结构,但这里的parent仍需要,因为我们找到的位置是nullptrwhile (cur)//找到需要插入位置的父亲{if (compare(kv, cur->_kv)){parent = cur;cur = cur->_left;}else if (compare(cur->_kv, kv)){parent = cur;cur = cur->_right;}elsereturn false;}cur = new Node(kv);if (compare(kv,parent->_kv))//判断插入的位置是父亲的左还是右{parent->_left = cur;cur->_parent = parent;}else{parent->_right = cur;cur->_parent = parent;}//检测是否满足红黑树特性,不满足则处理while (parent && parent->_color != BLACK){Node* grandfather = parent->_parent;Node* uncle = nullptr;if (parent == grandfather->_left)uncle = grandfather->_right;elseuncle = grandfather->_left;if (!uncle || uncle->_color == BLACK)//叔叔存在且为黑{if (parent == grandfather->_left && cur == parent->_left)//p为g左且c为p左,右单旋{RotateR(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else if (parent == grandfather->_right && cur == parent->_right)//p为g右且c为p右,左单旋{RotateL(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else if (parent == grandfather->_left && cur == parent->_right)//p为g左且c为p右,左右双旋{RotateL(parent);RotateR(grandfather);cur->_color = BLACK;grandfather->_color = RED;}else if (parent == grandfather->_right && cur == parent->_left)//p为g右且c为p左,右左双旋{RotateR(parent);RotateL(grandfather);cur->_color = BLACK;grandfather->_color = RED;}_root->_color = BLACK;break;}else//叔叔存在且为红{parent->_color = BLACK;uncle->_color = BLACK;grandfather->_color = RED;cur = cur->_parent;parent = cur->_parent;}	_root->_color = BLACK;}}return true;
}
验证是否平衡 

先计算一条路径的黑色节点个数,将其他路径与其进行比较,同时检测是否有连续的红色节点。

	bool IsBanlanceTree(){Node* cur = _root;int BlackNum = 0;while (cur)//计算一条路径的黑色节点{if (cur->_color == BLACK)BlackNum++;cur = cur->_left;}return _IsBanlance(_root,BlackNum,0);}
bool _IsBanlance(Node* root,int BlackNum,int Bnum)//每一个根节点的左右路径黑色节点Bnum是否都等于BlackNum
{if (root == nullptr){if (BlackNum != Bnum){cout << "每条路径上的黑色节点个数不相等" << endl;return false;}return true;}if (root->_parent&&root->_color==RED && root->_color == RED){cout << "有连续的红色节点" << endl;return false;}if (root->_color == BLACK)Bnum++;return _IsBanlance(root->_left, BlackNum, Bnum) && _IsBanlance(root->_right, BlackNum, Bnum);
}

4. 红黑树与AVL树的比较 

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O($log_2 N$),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

下文我们来看看红黑树封装map与set。

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

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

相关文章

嵌入式中STM32上模拟启动Linux自动初始化

Linux中有很多编程思想可以学习,很多大佬把这些思想、机制运用到单片机的编程上。 下文,在STM32上模拟Linux kernel自动初始化流程。 通常我们写程序都是按照这个套路,一个函数一个函数按照顺序逻辑一个一个的执行下去。 如果逻辑非常复杂,涉及的模块比较多,那么这种顺…

Quests system for Unity

一个简单而灵活的任务系统将帮助你实现所有的想法,而不需要事件和逻辑中的一堆额外代码! 我的资产是一个用于执行任务的独立系统。 特征: 任务逻辑不需要继承MonoBehaviour。 在一行中完成所需任务的激活/进度/完成。 易于理解的界面,包含项目中所有任务的列表。 不需要连接…

解锁!智能代码助手 Baidu Comate 硬核能力

近日&#xff0c;在全球软件开发大会上暨智能软件开发生态展上&#xff0c;来自 Baidu Comate 的资深研发工程师分享了精彩的专题演讲&#xff0c;小编整理了演讲精华&#xff0c;和大家一起玩转“大模型软件研发”。 今天带来——吴玮琦《智能代码助手 Baidu Comate 的核心能…

【Python时序预测系列】灰狼算法(GWO)优化LSTM实现单变量时间序列预测(案例+源码)

这是我的第279篇原创文章。 一、引言 灰狼算法&#xff08;GWO&#xff09;是一种新型的优化算法&#xff0c;灵感来源于灰狼群体中的社会行为。在灰狼算法中&#xff0c;每只灰狼都有自己的位置和适应度值&#xff0c;通过模拟灰狼群体的行为来搜索最优解。将灰狼算法应用于优…

支持不同业务模式与安全要求的跨网传输解决方案,了解一下

对于科技研发型企业来说&#xff0c;最值钱的是研发代码这类数据资产。因此很多企业会想将这些数据“困”在内部&#xff0c;防止数据泄露。最常见的做法是通过防火墙、DMZ区、双网卡主机、虚拟机、网闸/光闸等隔离方式&#xff0c;将网络划分为企业内外网&#xff0c;较为常见…

职校智慧校园现状及问题解决

近年来&#xff0c;智慧校园已经可以满足学校日常办公的需要&#xff0c;但是还是存在缺乏整体规划、缺乏统一技术标准、原有应用陈旧、多重身份和密码体系、业务系统的开发和维护模式不统一、现有应用重管理轻服务现象严重、数据资产利用不足等问题。 职校智慧校园现状及问题分…

Redis详解(二)

事务 什么是事务&#xff1f; 事务是一个单独的隔离操作&#xff1a;事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中&#xff0c;不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作&#xff1a;事务中的命令要么全部被执行&#xff0c;要么全部都…

怎么批量下载视频?DY视频爬虫在线提取采集工具

短视频批量下载工具&#xff0c;具有多种模块和功能&#xff0c;方便用户快速批量下载短视频。该软件的详细介绍&#xff1a; 功能模块介绍&#xff1a; 一. 搜索词批量搜索下载 视频关键词添加&#xff1a;支持添加多个视频关键词Q530269148进行全平台视频搜索。历史去重&a…

【全网瞩目】OpenAI春季发布会结束,一夜过后又惊喜——GPT4O,新的 LLM 标准诞生了

虽然昨天我就一直关注到OpenAI的主页提示&#xff0c;即将发布春季直播&#xff0c;而且也有很多媒体透露没有Sora&#xff0c;可能是AI Search等等&#xff0c;但是没想到结果还是这么惊喜。就连OpenAI方面也在直播前几天透露&#xff0c;不是搜索引擎&#xff0c;而是GPT的优…

vwmare虚拟机迁移磁盘方法

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理 虚拟机迁移磁盘的方法 简单方便快上手 当前目标 当前迁移文件: 当前位置&#xff1a; 目的地: e盘虚拟机文件夹 迁移到当前目录。 实际操作 先打开虚拟机的设置&#xff0c;找到这个虚拟机当前的位置…

渗透测试工具及插件第二期

一、OWASP Penetration Testing Kit 这个工具他集成了中间件&#xff0c;等版本信息&#xff0c;漏洞信息&#xff0c;url&#xff0c;标识头等信息&#xff0c;WAF/CDN识别&#xff0c;密匙等信息&#xff0c;多种信息的功能上集合的插件。 说明书&#xff1a;https://micros…

照明灯具十大排名都有哪些?市面上比较流行的十大护眼台灯品牌推荐

照明灯具十大排名都有哪些&#xff1f;护眼台灯排名当中靠前的主要有书客、飞利浦、松下等品牌。照明灯具作为家居与办公环境中不可或缺的元素&#xff0c;其品质与选择直接关系到人们的视觉健康与舒适度。本文将为大家揭示照明灯具的十大排名&#xff0c;让大家了解市场上最受…

SQL Server中怎么排查死锁问题

一、背景 我们在UAT环境压测的时候&#xff0c;遇到了如下的死锁异常。 Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 82) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Re…

Spring Cloud Alibaba 分布式配置中心(9)

项目的源码地址 Spring Cloud Alibaba 工程搭建&#xff08;1&#xff09; Spring Cloud Alibaba 工程搭建连接数据库&#xff08;2&#xff09; Spring Cloud Alibaba 集成 nacos 以及整合 Ribbon 与 Feign 实现负载调用&#xff08;3&#xff09; Spring Cloud Alibaba Ribbo…

C++深度解析教程笔记8

C深度解析教程笔记8 第17课 - 对象的构造&#xff08;上&#xff09;类定义中成员变量i和j的初始值&#xff1f;实验-成员变量的初始值对象初始化解决方案1实验-手动调用函数初始化对象对象初始化解决方案2&#xff1a;构造函数实验-构造函数小结 第18课 - 对象的构造&#xff…

Spring AI项目Open AI绘画开发指导

Spring AI项目创建 Spring AI简介创建Spring AI项目配置项目pom和application文件controller接口开发运行测试 Spring AI简介 Spring AI 是 AI 工程的应用框架。其目标是将 Spring 生态系统设计原则&#xff08;如可移植性和模块化设计&#xff09;应用于 AI&#xff0c;并推广…

【机器学习】机器学习与人工智能融合新篇章:自适应智能代理在多元化复杂环境中的创新应用与演进趋势

&#x1f512;文章目录&#xff1a; &#x1f4a5;1.引言 &#x1f68b;1.1 机器学习与人工智能的发展背景 &#x1f68c;1.2 自适应智能代理的概念与重要性 &#x1f690;1.3 研究目的与意义 ☔2.自适应智能代理的关键技术 &#x1f6e3;️2.1 环境感知与信息处理技术 …

RelationMap图谱--VUE,真实项目提供mock数据

RelationMap官网&#xff1a; 在线配置官网&#xff08;可以把数据放进去&#xff0c;直接看效果&#xff09; VUE2 效果&#xff1a;左侧列表栏&#xff0c;点击右侧显示对应的图谱 代码&#xff1a;按照代码直接贴过去&#xff0c;直接出效果 relationMap/index.vue <te…

泽攸科技无掩模光刻机:引领微纳制造新纪元

在当今科技迅猛发展的时代&#xff0c;微纳制造技术正变得越来越重要。泽攸科技作为这一领域的先行者&#xff0c;推出了其创新的无掩模光刻机&#xff0c;这一设备在微电子制造、微纳加工、MEMS、LED、生物芯片等多个高科技领域展现出了其独特的价值和广泛的应用前景。 技术革…

Python-VBA函数之旅-tuple函数

目录 一、tuple函数的常见应用场景 二、tuple函数使用注意事项 三、如何用好tuple函数&#xff1f; 1、tuple函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、tu…