【C++杂货铺】红黑树
目录
🌈前言🌈
📁 红黑树的概念
📁 红黑树的性质
📁 红黑树节点的定义
📁 红黑树的插入操作
📁 红黑树和AVL树的比较
📁 全代码展示
📁 总结
🌈前言🌈
欢迎大家观看本期【C++杂货铺】,本期内容将讲解二叉搜索树的进阶——红黑树。红黑树是一种二叉搜索树,通过控制每个节点的颜色,来调整整棵树的高度。
红黑树是set和map实现的底层实现,在下一期内容,我们将讲解STL中set和map的模拟实现。如果你对二叉搜索树还不是很了解,可以快速阅览下面这篇文章;
【C++杂货铺】二叉搜索树-CSDN博客
📁 红黑树的概念
红黑树,是一种二叉搜索树,在每个节点增加一个存储位表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而接近平衡的。
📁 红黑树的性质
1. 每个节点不是红色就是黑色;
2. 根节点是黑色的;
3. 如果一个节点是红色的,那么它的两个孩子节点是黑色的;
4. 对于每个节点,从该节点到其他所有后代叶节点的简单路径上,均包含相同数目的黑色节点个数;
5. 每个叶子结点都是黑色的(此后的叶子结点指的是空节点)
📁 红黑树节点的定义
// 节点的颜色
enum Color{RED, BLACK};
// 红黑树节点的定义
template<class ValueType>
struct RBTreeNode
{RBTreeNode(const ValueType& data = ValueType(),Color color = RED): _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr), _data(data), _color(color){}RBTreeNode<ValueType>* _pLeft; // 节点的左孩子RBTreeNode<ValueType>* _pRight; // 节点的右孩子RBTreeNode<ValueType>* _pParent; // 节点的双亲(红黑树需要旋转,为了实现简单给
出该字段)ValueType _data; // 节点的值域Color _color; // 节点的颜色
};
📁 红黑树的插入操作
红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
1. 按照二叉搜索树规则插入新节点;
新插入节点的默认颜色是红色。因为红色容易控制规则,如果默认插入黑色,需要保证从当前节点到叶子节点具有相同的黑色节点个数,不易控制。
即先保证性质4不被违反,再来判断性质3是否被违反,如果违反就进行调整。
2. 检测新节点插入后,红黑树的性质是否遭到破坏。
如果双亲节点的颜色是黑色,没有违反规则,则不需要调整;当新插入节点的双亲节点颜色为红色时,就违反了性质3,即不能有连续在一起的红色节点,此时需要进行调整,可分为两种情况:
约定:cur为当前节点,p为父亲节点,g为祖父节点,u为叔叔节点
● 情况1:cur为红,p为红,g为黑,u存在且为红
● 情况2:cur为红,p为红,g为黑,u存在且为黑 或者 u不存在
当如子树如下图所示时,需要对红黑树进行双旋,先以p为根进行左旋,再以g为根进行右旋。下图是p在g的左子树的情况,考虑一下p在g的右子树,且cur为p的左子树的情况。
📁 红黑树和AVL树的比较
红黑树和AVL数都是搞笑的平衡二叉树,增删查改的时间复杂度都是O(log N),红黑树不追求绝对平衡,其只需要保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL数更优,而且红黑树的实现比较简单,所以实际应用中红黑树更多。
map和set的底层就是红黑树。
📁 全代码展示
template <class T>
struct RBTreeNode
{typedef RBTreeNode<T> Node;RBTreeNode(const T& val = T()):_left(nullptr), _right(nullptr), _parent(nullptr), _val(val), _color(RED){}Node* _left;Node* _right;Node* _parent;T _val;Color _color;
};template<class T>
class RBTree
{typedef RBTreeNode<T> Node;
public:bool Insert(const T& val){if (_root == nullptr){_root = new Node(val);_root->_color = Black;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_val > val){parent = cur;cur = cur->_left;}else if (cur->_val < val){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(val);if (parent->_val < val){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//调整颜色,不能出现连续的红色while (parent && parent->_color == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){//叔叔在右边//1. 叔叔存在,且为红色Node* uncle = grandfather->_right;if (uncle && uncle->_color == RED){grandfather->_color = RED;uncle->_color = parent->_color = Black;cur = grandfather;parent = cur->_parent;}//2. 叔叔存在,且为黑色 || 叔叔不存在else{/*gp uc */if (cur == parent->_left){RotateR(grandfather);parent->_color = Black;grandfather->_color = RED;}/*gp uc*/else{RotateL(parent);RotateR(grandfather);cur->_color = Black;grandfather->_color = RED;}break;}}else{//叔叔在左边//1. 叔叔存在,且为红色Node* uncle = grandfather->_left;if (uncle && uncle->_color == RED){grandfather->_color = RED;parent->_color = uncle->_color = Black;cur = grandfather;parent = cur->_parent;}//2. 叔叔存在,且为黑色 || 叔叔不存在else{/*gu pc*/if (cur == parent->_right){RotateL(grandfather);parent->_color = Black;grandfather->_color = RED;}/*gu pc */else{RotateR(parent);RotateL(grandfather);cur->_color = Black;grandfather->_color = RED;}break;}}}_root->_color = Black;return true;}//遍历
void InOrder()
{_InOrder(_root);cout << endl;
}bool isBalance()
{if (_root == nullptr){return true;}int BlackNum = 0;Node* cur = _root;while (cur){if (cur->_color == Black)BlackNum++;cur = cur->_right;}return _isBalance(_root,0,BlackNum);
}protected:bool _isBalance(Node* root,int count , const int& BlackNum){if(root == nullptr){if (count != BlackNum)return false;return true;}if (root->_color == RED && root->_parent->_color == RED){cout << "red" << endl;return false;}if (root->_color == Black)count++;return _isBalance(root->_left,count,BlackNum)&& _isBalance(root->_right,count,BlackNum);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_val << endl;_InOrder(root->_right);}//左单旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;subR->_left = parent;Node* pparent = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (parent == pparent->_right){pparent->_right = subR;}else{pparent->_left = subR;}subR->_parent = pparent;}}//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;subL->_right = parent;Node* pparent = parent->_parent;parent->_parent = subL;if (parent == _root){_root = subL;_root->_parent = nullptr;}else{if (parent == pparent->_right){pparent->_right = subL;}else{pparent->_left = subL;}subL->_parent = pparent;}}
private:Node* _root = nullptr;
};
📁 总结
以上就是本期【C++杂货铺】的主要内容了,讲解了红黑树如果优化二叉搜索树,红黑树的概念,红黑树实现插入,以及红黑树的高度平衡调整,此外模拟实现了红黑树。
如果感觉本期内容对你有帮助,欢迎点赞,收藏,关注Thanks♪(・ω・)ノ
相关文章:

【C++杂货铺】红黑树
目录 🌈前言🌈 📁 红黑树的概念 📁 红黑树的性质 📁 红黑树节点的定义 📁 红黑树的插入操作 📁 红黑树和AVL树的比较 📁 全代码展示 📁 总结 🌈前言…...

css--控制滚动条的显示位置
各种学习后的知识点整理归纳,非原创! ① direction属性 滚动条在左侧显示② transform:scaleY() 滚动条在上侧显示 正常的滚动条会在内容超出规定的范围后在区域右侧和下侧显示在有些不正常的需求下会希望滚动条在上侧和左侧显示自己没有想到好的解决方案…...

华为设备display查看命令
display version //查看版本信息 display current-configuration //查看配置详情 display this //查看当前视图有效配置 display ip routing-table //查看路由表 display ip routing-table 192.168.3.1 //查看去往3.1的路由 display ip interface brief //查看接口下ip信息 dis…...

自动攻丝机进出料激光检测 进料出料失败报警循环手动及关闭报警退出无限循环
/**************进料检测********************/ /***缺料无限次循环 手动退出 超时报警*******/ void check_Pon() // { zstatus0; //报警计数器归零 Signauto1; …...

2024年去除视频水印的5种方法
如果你从事电影剪辑或者视频编辑工作,你经常需要从优酷、抖音、TikTok下载各种视频片段……。 通常这些视频带有水印和字幕。一些免费软件如CapCut、canva、Filmora也会给你制作的视频打上水印,这些水印嵌入在视频内部。 2024年去除视频水印的5种方法 …...

怎么用电脑接收手机文件 用备忘录传输更舒服
在这个数字化时代,手机已经成为我们随身携带的“百宝箱”,里面装满了各种重要的文件、资料和信息。然而,有时我们需要在电脑上处理这些文件,比如编辑文档、制作PPT或是查看照片。那么,如何在电脑与手机之间实现文件的顺…...

微信小程序、uniapp密码小眼睛
直接上代码喔喔喔喔喔喔喔喔~~ <input name"username" password"{{passwordHideShow}}" placeholder-style"color:#bdbdbd" type"text"maxlength"20" value"{{passwordNumber}}" bindinput"passwordInput…...

【手势操作-复习前一天的内容-预习今天的内容 Objective-C语言】
一、昨天呢,我们学习的是这个,事件 1.事件这一块儿呢,iOS事件,分为三大类, 1)触摸事件 2)加速计事件 3)远程控制事件 2.这个里边呢,我们主要学习的是这个触摸事件,触摸事件里边,就是Touch,touchesBegan:方法里边,有一个touches参数,它是set类型的, 3.Set,…...

【收录 Hello 算法】第 6 章 哈希表
目录 第 6 章 哈希表 本章内容 第 6 章 哈希表 Abstract 在计算机世界中,哈希表如同一位聪慧的图书管理员。 他知道如何计算索书号,从而可以快速找到目标图书。 本章内容 6.1 哈希表6.2 哈希冲突6.3 哈希算法6.4 小结...

rust类型和变量(二)
基础知识 Rust中的变量基础知识 1.在Rust中,使用Iet关键字来声明变量 2.Rust支持类型推导,但你也可以显式指定变量的类型: Ietx:i325;/显式指定x的类型为i32 3.变量名蛇形命名法(Snake Case),i 而枚举和结构体命名使用帕斯卡命名法(Pasca|Ca…...

linux学习:多媒体开发库SDL+视频、音频、事件子系统+处理yuv视频源
目录 编译和移植 视频子系统 视频子系统产生图像的步骤 api 初始化 SDL 的相关子系统 使用指定的宽、高和色深来创建一个视窗 surface 使用 fmt 指定的格式创建一个像素点编辑 将 dst 上的矩形 dstrect 填充为单色 color编辑 将 src 快速叠加到 dst 上编辑 更新…...

基于门控的循环神经网络:LSTM
之前我们介绍了循环神经网络的原理以及实现。但是循环神经网络有一个问题,也就是长期依赖问题。我们之前的01序列预测案例中可以看到,当序列长度到达10以上之后错误就会增多,说明简单的RNN记忆容量较小,当长度更大时就不怎么适用了…...

Web常见的攻击方式及其防御策略
随着互联网技术的快速发展,Web应用已成为我们日常生活和工作中不可或缺的一部分。然而,Web应用也面临着各种安全威胁和攻击。了解这些常见的攻击方式,并采取有效的防御策略,对于保护Web应用的安全至关重要。 一、常见的Web攻击方…...

关于SQL
数据库简介: 数据库分类 关系型数据库模型: 优点:易于维护,可以实现复杂的查询 缺点:海量数据 读取写入性能差,高并发下数据库的io是瓶颈 是把复杂的数据结构归结为简单的二元关系(即二维表…...

大模型时代下两种few shot高效文本分类方法
介绍近年(2022、2024)大语言模型盛行下的两篇文本分类相关的论文,适用场景为few shot。两种方法分别是setfit和fastfit,都提供了python的包使用方便。 论文1:Efficient Few-Shot Learning Without Prompts 题目:无需提示的高效少…...

Linux0.11 中全局描述符表(GDT)
在Linux内核中,全局描述符表(Global Descriptor Table,简称GDT)是一个关键的数据结构,主要用于管理处理器的内存段和相关的权限与属性。它属于x86架构中的保护模式特性,允许操作系统对内存访问进行更精细的…...

搜维尔科技:数据手套用于外固定虚拟现实模拟 、外固定增强现实模拟
数据手套用于外固定虚拟现实模拟、外固定增强现实模拟 搜维尔科技:数据手套用于外固定虚拟现实模拟、外固定增强现实模拟...

《三》菜单栏_工具栏_状态栏动作与实现
上期我们创建了辣么多的动作,那么这次我们要是开始实现这些动作,撸起袖子来吧: //菜单动作(ACtion)QAction *newAct;//新建QAction *openAct;//打开QAction *saveAct;//保存QAction *saveAsAct;//另存为QAction *prin…...

基于NTP服务器获取网络时间的实现
文章目录 1 NTP1.1 简介1.2 包结构1.3 UNIX 时间戳和NTP时间戳 2 代码实现2.1 实现步骤2.2 完整代码 3 结果 在某些场景下,单片机需要通过网络获取准确的时间进行数据同步,例如日志记录、定时任务等。然而,单片机本身无法直接获得准确的标准时…...

Web APIs(获取元素+操作元素+节点操作)
目录 1.API 和 Web API 2.DOM导读 DOM树 3.获取元素 getElementById获取元素 getElementsByTagName获取元素 H5新增方法获取 获取特殊元素 4.事件基础 执行事件 操作元素 修改表单属性 修改样式属性 使用className修改样式属性 获取属性的值 设置属性的值 移除…...
Android adb shell关于CPU核的命令
Android adb shell关于CPU核的命令 先使用命令: adb shell 进入控制台。 然后,直接在$后面输入下面命令,针对CPU的命令。 cat /proc/cpuinfo | grep ^processor | wc -l 查看当前手机的CPU是几核的。 cat sys/devices/system/cpu/online …...

基于springboot+mybatis+vue的项目实战之页面参数传递
如图所示,删除操作可以用按钮实现,也可以用超链接来实现。 1、第一种情况,用按钮实现。 html页面相关: <button type"button" click"deleteId(peot.id)">删除</button> <script>new Vue(…...

CSS-浮动
float (浮动) 作用:盒子的顶点是一样的,具备行内块的特征,能设置宽高 属性:float 属性值:left 浮动在网页左边 right 浮动在网页右边 .a{width: 100px;height: 100px;float:left;background-color: red;}.b…...

MFC:字符串处理
例子 //多字节char* szTest "abc多字节";int nLen strlen(szTest);//9//宽字节wchar_t* szTest2 L"abc多字节";int nlen2 wcslen(szTest2);//6//测试项目配置为Unicodewchar_t* szTesz3 TEXT("abcd");//char* -> CStringCString strTes…...

虚拟仿真云平台在教育应用中的优势和意义
虚拟仿真云实验教学平台作为一种新型的教学方法,近年来在高校教育中得到了十分广泛的应用。它通过模拟真实的实验场景和实验操作,让学生在计算机上进行实验操作和数据处理,为学生提供了更加便捷、可靠、有效的实验学习环境。本文,…...

CPU的的处理流程如何快速记忆
为了快速记忆CPU的处理流程,可以将其简化成五个主要阶段,通常称为“冯诺依曼架构”的五个基本步骤,或者是流水线处理的几个阶段。下面是一种便于记忆的简化版本: CPU处理流程的五个阶段: 取指令(Instructi…...

AI视频教程下载:基于OpenAl、LangChain、 Replicate开发AI应用程序
欢迎来到令人兴奋的 AI 应用世界!在这门课程中,你将学习到创建一个能够与用户互动、理解自然语言、处理音频输入,甚至分析图像的真正智能应用所需的技能和技术。 AI 工具和技术 你将获得使用几个知名 AI API 和技术的实际经验。这些行业领先…...

【C++】继承相关(基类与派生类的继承关系以及细节整理)
目录 00.引言 01.继承的定义 02.基类和派生类对象 03.继承中的作用域 04.派生类的默认成员函数 05.友元、静态成员 00.引言 继承是面向对象编程中的一个重要概念,它的作用是创建一个新的类,该类可以从一个已存在的类(父类/基类&#x…...

【Web后端】监听器Listener
1、简介 用来监听Servlet组件对象状态发生变化的组件可以监听的源包括:ServetRequest、HttpSession、ServletContext当监听到事件源状态发生变化时,会有对应的响应行为 2、使用方法 在web.xml文件中配置 <listener> <listener-class>com.coder.util.…...

C/C++ 初级球球大作战练手
效果演示: https://live.csdn.net/v/385490 游戏初始化 #include <stdbool.h> #include<stdio.h> #include<stdlib.h> #include<time.h> #include<graphics.h> #include <algorithm> #include<math.h> #include<mmsy…...