【C++进阶学习】第八弹——红黑树的原理与实现——探讨树形结构存储的最优解

二叉搜索树:【C++进阶学习】第五弹——二叉搜索树——二叉树进阶及set和map的铺垫-CSDN博客

AVL树:

​​​​​​【C++进阶学习】第七弹——AVL树——树形结构存储数据的经典模块-CSDN博客

前言:

在前面,我们已经学习了二叉搜索树和它的改进AVL树,今天,我们来学习另一种由二叉搜索树改进而来的树形结构——红黑树

目录

一、红黑树的概念

二、红黑树的性质

三、红黑树的节点结构

四、红黑树的操作

五、红黑树的实现代码

六、总结


一、红黑树的概念

红黑树是一种特殊的二叉树,它的每个节点都增加一个存储为表示颜色,要么是黑色,要么是白色。并且通过对每条路径上添加节点时节点的颜色限制,来确保每个路径上的黑色节点数量一致,且最长路径长度最多是最短路径长度的两倍,因此达到平衡。

二、红黑树的性质

红黑树有以下五个性质:

  1. 节点是红色或黑色:每个节点都有一个颜色属性,颜色可以是红色或黑色。

  2. 根节点是黑色:树的根节点必须是黑色。

  3. 红色节点的子节点是黑色:如果一个节点是红色,则它的两个子节点必须是黑色(即不能有两个连续的红色节点)。

  4. 每个节点到其每个叶子节点的路径都包含相同数量的黑色节点:从任何节点到其每个叶子节点的路径上,经过的黑色节点的数量必须相同。

  5. 叶子节点是黑色:红黑树的叶子节点(通常是指空节点)被视为黑色。

三、红黑树的节点结构

template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;    //左子树BSTreeNode<K, V>* _right;   //右子树BSTreeNode<K, V>* _parent;  //父亲pair<K, V> _kv;       //存放节点值的string _col;    //颜色(通过这个可以直到左右子树存在情况)//构造函数BSTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col("RED")     //默认颜色为红色{}
};

红黑树的节点结构与二叉搜索树和AVL树差别不大,最大的差别就是加入了一个新的存储点——颜色

四、红黑树的操作

红黑树的基本操作包括插入、删除和查找。以下是这些操作的简要说明:

  1. 插入

    • 将新节点插入到树中,初始时将其标记为红色。
    • 可能会破坏红黑树的性质,需要通过旋转和重新着色来恢复性质。
  2. 删除

    • 删除节点后,可能会破坏红黑树的性质。
    • 需要进行调整,包括旋转和重新着色,以恢复红黑树的性质。
  3. 查找

    • 查找操作与普通的二叉搜索树相同,通过比较节点值来决定向左或向右子树查找。

在这几个操作中,插入是红黑树的关键,因为这是构造红黑树的关键,怎样插入才能保证红黑树的节点颜色、路径长度符合规定,下面我们就来重点讲解一下红黑树的节点插入操作:

首先我们要先清楚一点,红黑树也是二叉搜索树,所以它肯定是符合二叉搜索树的性质的——左边子树值小于根,右边子树值大于根

问题的关键是如何保证插入后结构的颜色符合规定,要做到这一点,我们首先就先要摸清插入节点会遇到的所有情况,然后我们再分析如何解决这些情况:

(强调一下:一定要把前面AVL树中讲的左右旋先弄明白)

假设:cur表示当前节点,p表示父节点,g表示祖父节点,u为叔叔节点

情况一:cur为红,p为黑

情况二: cur为红,p为红,g为黑,u存在且为红

解决方法:把p、u变成黑,g变为红,然后让g变为cur继续向上处理 

情况三:cur为红,p为红,g为黑,u不存在

解决方法:把p变为黑,g变为红,然后进行左旋/右旋

情况四:cur为红,p为红,g为黑,u存在且为黑

解决方法:把p变为黑,g变为红,同时右旋/左旋

特殊情况:如果当cur的插入位置形似AVL树中的RL型或LR型时,要先进行旋转转换成上面几种情况

五、红黑树的实现代码

RBTree.h

//红黑树
#include<iostream>
using namespace std;template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;    //左子树BSTreeNode<K, V>* _right;   //右子树BSTreeNode<K, V>* _parent;  //父亲pair<K, V> _kv;       //存放节点值的string _col;    //颜色(通过这个可以直到左右子树存在情况)//构造函数BSTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col("RED")     //默认颜色为红色{}
};template<class K, class V>
class BSTree
{typedef BSTreeNode<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->_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;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//按搜索二叉树规则插入到指定位置后,再检验一下是否符合红黑树的规则进行相关调整while (parent && parent->_col == "RED")    //当父节点存在且父节点为红时,进行相关调整{Node* grandfather = parent->_parent;if(parent==grandfather->_left)       //p为g的左孩子时{//     g//   p       Node* uncle = grandfather->_right;if (uncle && uncle->_col == "RED")    //u存在且为红{//       g//    p      u// curparent->_col = uncle->_col = "BLACK";grandfather->_col = "RED";//继续往上更新cur = grandfather;parent = cur->_parent;}else                               //u不存在/u存在且为黑{//       g//     p//  curif (cur == parent->_left){RotateR(grandfather);grandfather->_col = "RED";parent->_col = "BLACK";}else{//LR型RotateL(parent);RotateR(grandfather);cur->_col = "BLACK";grandfather->_col = "RED";}break;}}else                      //p为g的右孩子时,与上面的相反即可{Node* uncle = grandfather->_left;if (uncle && uncle->_col == "RED"){parent->_col = uncle->_col = "BLACK";grandfather->_col = "RED";//继续往上更新cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){//       g//     u    p//            cRotateL(grandfather);grandfather->_col = "RED";parent->_col = "BLACK";}else{//       g//     u   p//        c//RL型RotateR(parent);RotateL(grandfather);cur->_col = "BLACK";grandfather->_col = "RED";}break;}}}_root->_col = "Black";return true;}//进行旋转调整(旋转操作与AVL树中的完全一样,不明白的可以看我之前的文章)void RotateL(Node* parent)   //左单旋{Node* subR = parent->_right;Node* subRL = subR->_left;Node* parentParent = parent->_parent;parent->_right = subRL;subR->_left = parent;if(subRL)subRL->_parent = parent;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}parent->_parent = subR;}void RotateR(Node* parent)   //右单旋{Node* subL = parent->_left;Node* subLR = subL->_right;Node* parentParent = parent->_parent;parent->_left = subLR;subL->_right = parent;if (subLR){subLR->_parent = parent;}if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}parent->_parent = subL;}//中序打印void Inorder(){_Inorder(_root);cout << endl;}void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_kv.first << " ";_Inorder(root->_right);}//检查是否为BS树(检查两点)//一:是否有连续的红节点//二:各个路径上的黑色节点个数是否相等bool Check(Node* root,int blacknum,const int refVal){if (root == nullptr){if (blacknum != refVal){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, refVal)       //红黑树的左右子树也是红黑树&& Check(root->_right, blacknum, refVal);     //所以要用递归对左右子树也进行判断}bool IsBalance(){if (_root == nullptr)return true;if (_root->_col == "RED")return false;int refVal = 0;      //参考值Node* cur = _root;while (cur){if (cur->_col == "BLACK"){++refVal;}cur = cur->_left;}int blacknum = 0;    //根节点到当前节点黑色节点数量return Check(_root, blacknum,refVal);}private:Node* _root = nullptr;
};

RBTree.c

//红黑树
int main()
{int a[] = { 4,2,6,1,3,5,15,7,16,14 };   //int a[] = { 790,760,969,270,31,424,377,24,702 };BSTree<int, int> t;for (auto e : a){t.Insert(make_pair(e, e));}t.Inorder();cout << "是否是红黑树(1/0):"<<t.IsBalance() << endl;return 0;
}

运行结果:

六、总结

以上就是红黑树的全部内容,红黑树因为其自平衡的特性,及通过节点颜色来操作其树形结构的特点,极大的提高了数据存储及处理的效率,需要我们好好掌握

感谢各位大佬观看,创作不易,还请各位大佬一键三连!!!

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

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

相关文章

PCIe 6.0为什么需要14-bit tag

1.TLP中的tag是什么 在PCIe TLP&#xff08;Transaction Layer Packet&#xff09;中&#xff0c;tag是分配给特定Non-Posted Request的编号&#xff0c;协议要求CPL/CPLD中的tag 与对应non-post request TLP中的tag保持一致&#xff0c;因此Requester可以使用tag来识别CPL…

免费【2024】springboot 趵突泉景区的智慧导游小程序

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

十、SpringBoot 统⼀功能处理【拦截器、统一数据返回格式、统一异常处理】

十、SpringBoot 统⼀功能处理 1. 拦截器【HandlerInterceptor、WebMvcConfig】1.1 拦截器快速⼊⻔⾃定义拦截器&#xff1a;实现HandlerInterceptor接⼝&#xff0c;并重写其所有⽅法注册配置拦截器&#xff1a;实现WebMvcConfigurer接⼝&#xff0c;并重写addInterceptors⽅法…

堆(c++)

堆是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。 堆总是满足下列性质&#xff1a; 堆中某个节点的值总是不大于或不小于其父节点的值&#xff1b;堆总是一棵完全二叉树。 常见的堆有二叉堆、斐波那契堆等。 堆是非线性数据结构&#…

初识C++ · map和set的使用

目录 前言&#xff1a; 1 set 2 map 前言&#xff1a; 在前面阶段&#xff0c;我们已经学习了stl里面的部分容器&#xff0c;比如vector,list,deque等&#xff0c;这些容器都被称为序列式容器&#xff0c;也就是每个值之间式没有关联的&#xff0c;那么今天介绍的容器&…

IGV.js | 载入自己下载的gtf文件

1.安装 htslib-1.20 https://www.htslib.org/doc/tabix.html J3$ cd ~/Downloads/ $ wget https://github.com/samtools/htslib/releases/download/1.20/htslib-1.20.tar.bz2 $ tar jxvf htslib-1.20.tar.bz2编译安装&#xff1a; $ cd htslib-1.20/ $ ./configure --prefix/…

vue的三大核心知识点

响应式&#xff1a; 监听data属性getter setter(包括数组)模板编译&#xff1a; 模板到render函数再到vnodevdom&#xff1a; patch(elem, vnode)和patch(vnode, newVnode) vue组件初次渲染过程 解析模板为render函数&#xff08;或在开发环境已完成&#xff0c;vue-loader&a…

WIX Toolset 3.11 对本地化的支持方案

1.准备主题文件和本地化文件 WIX Toolset种主题文件为xml文件&#xff0c;负责配置控件的布局&#xff0c; 本地化文件为wxl文件&#xff0c;负责配置待加载的字符串&#xff0c;主题文件根据ID加载需要显示的文字内容。考虑到英文和中文字符长度大小不一&#xff0c;所以这里…

渗透测试——prime1靶场实战演练{常用工具}端口转发

文章目录 概要信息搜集 概要 靶机地址&#xff1a;https://www.vulnhub.com/entry/prime-1,358 信息搜集 nmap 扫网段存活ip及端口 找到除了网关外的ip&#xff0c;开放了80端口&#xff0c;登上去看看 是一个网站&#xff0c;直接上科技扫一扫目录 python dirsearch.py -u …

尝试带你理解 - 进程地址空间,写时拷贝

序言 在上一篇文章 进程概念以及进程状态&#xff0c;我们提到了 fork 函数&#xff0c;该函数可以帮我们创建一个子进程。在使用 fork 函数时&#xff0c;我们会发现一些奇怪的现象&#xff0c;举个栗子&#xff1a; 1 #include <stdio.h>2 #include <unistd.h>3 …

跟《经济学人》学英文:2024年07月20日这期 The Russell 2000 puts in a historic performance

Why investors have fallen in love with small American firms The Russell 2000 puts in a historic performance 罗素2000指数&#xff1a; 罗素2000指数&#xff08;英语&#xff1a;Russell 2000 Index&#xff09;为罗素3000指数中收录市值最小的2000家&#xff08;排序…

学习笔记 韩顺平 零基础30天学会Java(2024.7.25)

P425 枚举类引出 举了一个例子&#xff0c;季节类创建对象&#xff0c;但是根据Java的规则&#xff0c;可以设置春夏秋冬以外的对象&#xff0c;而且可以修改&#xff0c;这样就会不符合实际&#xff0c;因此引出枚举 P426 自定义枚举类 1.构造器私有化&#xff0c;使外面没有办…

深入解析 GPT-4o mini:强大功能与创新应用

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

C++ 列式内存布局数据存储格式 Arrow

Apache Arrow 优点 : 高性能数据处理&#xff1a; Arrow 使用列式内存布局&#xff0c;这特别适合于数据分析和查询操作&#xff0c;因为它允许对数据进行高效批量处理&#xff0c;减少CPU缓存未命中&#xff0c;从而提升处理速度。 零拷贝数据共享&#xff1a; Arrow …

【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常

问题现象 客户的java日志中有如下异常信息&#xff1a; 问题的风险及影响 对正常的业务流程无影响&#xff0c;但是影响druid的merge sql功能&#xff08;此功能会将sql语句中的字面量替换为绑定变量&#xff0c;然后将替换以后的sql视为同一个&#xff0c;然后用做执行性能统…

Vue3扁平化Tree组件的前端分页实现

大家好&#xff0c;我是小卷。得益于JuanTree的扁平化设计&#xff0c;在数据量很大的情况下除了懒加载&#xff0c;使用前端分页也是一种解决渲染性能问题的可选方案。 用法 要实现的文档&#xff1a; 分页效果&#xff1a; 实现 新增属性&#xff1a; 组件setup方法中新增…

程序员加班现象:成因、影响与应对策略

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 加班的成因 加班的影响 应对策略 结语 我的其他博客 前言 在现代科技行业中&#xff0c;加班现象已成为一个普遍存在的问题…

配置sublime的中的C++编译器(.sublime-build),实现C++20

GCC 4.8: 支持 C11 (部分) GCC 4.9: 支持 C11 和 C14 (部分) GCC 5: 完全支持 C14 GCC 6: 支持 C14 和 C17 (部分) GCC 7: 支持 C17 (大部分) GCC 8: 完全支持 C17&#xff0c;部分支持 C20 GCC 9: 支持更多的 C20 特性 GCC 10: 支持大部分 C20 特性 GCC 11: 更全面地支持 C20 …

ES中的数据类型学习之ARRAY

Arrays | Elasticsearch Guide [7.17] | Elastic 中文翻译 &#xff1a;Array Elasticsearch 5.4 中文文档 看云 Arrays In Elasticsearch, there is no dedicated array data type. Any field can contain zero or more values by default, however, all values in the a…

SpringBoot 自动配置原理

一、Condition Condition 是在 Spring 4.0 增加的条件判断功能&#xff0c;通过这个可以功能可以实现选择性的创建 Bean 操 作。 思考&#xff1a; SpringBoot 是如何知道要创建哪个 Bean 的&#xff1f;比如 SpringBoot 是如何知道要创建 RedisTemplate 的&#xff1f; …