C++进阶——红黑树

1.红黑树的概念及其介绍

红黑树是一种近似平衡的二叉搜索树,与AVL树极为相似,红黑树的主要特点在于它通过约束树中节点的颜色和其他规则,确保树的高度始终接近对数时间复杂度,从而使常见操作(如插入、删除、查找)能够在 O(log n) 时间内完成。

2.红黑树的特性

红黑树的每个结点上都有一个存储位,用于表示该结点的颜色,节点的颜色只有两种,分别是RED(红色)或BLACK(黑色),这也是为什么其名为红黑树的原因。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近近似平衡。

红黑树具有以下特性:

  1. 结点不是红色就是黑色。
  2. 根节点是黑色的。
  3. 不能有连续的红色节点。
  4. 对于每个结点,从该结点到其所有后代叶结点的路径上,均包含相同数目的黑色结点。
  5. 每个叶子的左右空结点都算做为黑色。

2.1红黑树的节点着色

红黑树通过节点着色来控制较高一侧树高不会超过另一侧树高的两倍。其原理是由于不能有连续的红色节点,而每个节点到其后代所以叶子节点的黑色节点数都是一样的,所以一个节点的最长路径最多只能是红黑节点交替的,而最短的路径最短也只能是连续的黑色节点,所以对于一个节点的最长路径是必然不可能会大于其最短路径的两倍的,通过这种方式红黑树控制树的高度差,可将二叉搜索树近似看作为一颗平衡二叉树。

3.红黑树的基本结构

在了解红黑树之前,我想介绍一下使用于红黑树中的STL容器:pair ,pair对于红黑树十分重要,需要我们了解并知晓如何使用。

3.1pair容器的使用

pair 是定义在 头文件 <utility> 中的一个模板类,常用于表示一个二元组或元素对,且其提供了按照字典序对元素对进行大小比较的比较运算符模版函数。

pair的使用

pair< 类型1,类型2> 类名 

pair容器中存放两个值,从左往右依次是,K值、V值。

两个值的访问通过:类名.first  和  类名.second 来访问。

在创建时可不赋值通过默认构造来创建,或者带有参数的构造函数创建一个空对象,也可通过相同类的对象拷贝构造的去赋值创建。

pair重载运算符的使用

pair的运算符的使用的逻辑是按照先依次比较first、second的数据来判断使用的,只有当两个pair对象的first、second两个值都相等时,才算相等,而当比较大小时,只要first大的就更大,当first一样大时再通过比较second中的值来比较确定大小。

make_pair( ) 函数

对于pair的使用显得较为麻烦,每次都要指明pair中存储的两个值的类型,而make_pair( )函数通过封装使用pair类的使用可以不用的显示两个存储值的类型。

需要注意的是make_pair()函数的本质是一个函数,通过两个参数值创建对应的pair类型的对象作为函数的返回值

3.2红黑树的创建

红黑树相比AVL树,取消了平衡因子这一概念,引入了树节点着色的方式来限制左右树高,其它基本结构与AVL树基本一致。

enum  Color
{RED,BLACK,
};template<class K, class V>
struct RBTreeNode
{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _col;pair<K, V> _kv;RBTreeNode(const pair<K, V> kv):_left(nullptr), _right(nullptr), _parent(nullptr), _col(RED), _kv(kv){}
};template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
private:Node* _root = nullptr;
public://成员函数
}

在红黑树中,我们使用了pair类作为红黑树的成员变量,此外,通过枚举enum来定义每个树节点的数颜色。

3.3红黑树的数据插入

红黑树的数据插入同样是最需要我们重点关注的地方,需要我们理解其控制数高度的方式,以及树节点的着色。

对于节点的着色,除了根节点以外,其他新节点的插入都默认是红色着色,其节点的插入的难点在于维持每条路径上的黑树节点数是相同的,为了维持这个特性,红黑树同样需要用到AVL树中的旋转调整树来完成对节点颜色的控制,从而达到控制树高的目的,但不同于AVL树的平衡因子,红黑树在旋转调整树的操作之后需要更改树节点的颜色,这个对于不同情况的处理不同。

bool insert(const pair<K, V>&  kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;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);cur->_parent = parent;if (cur->_kv.first > parent->_kv.first)//cur为parent右节点{parent->_right = cur;}else //cur为parent左节点{parent->_left = cur;}//修改颜色cur->_col = RED;//新节点着色默认为红色while (parent && parent->_col == RED){Node* grandfather = parent->_parent;//由于parent为红色,一定有上一节点,所以不需要讨论grandparent的存在情况if (parent == grandfather->_left)//parent为左子树{Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED)//uncle存在且为红{uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//uncle不存在,或者存在为黑{if (cur == parent->_right){RotateL(parent);std::swap(cur, parent);}RotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;break;}}else if(grandfather && parent == grandfather->_right)//parent为右子树{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED)//uncle存在且为红{uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//uncle不存在,或者存在为黑{if (cur == parent->_left){RotateR(parent);std::swap(cur, parent);}RotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;break;}}}_root->_col = BLACK;return true;
}

为了更加方便的表述各个节点间的关系,我们使用:

cur表示待插入的新节点(或调整起始节点),p节点(parent)为cur的上一节点,g节点(grandparent)为p的上一节点,u节点(uncle)为g节点的另一个孩子节点

根据处理的情况不同,大致分为以下几种情况:

  1. 当根节点为空时,此时cur充当根节点。
  2. p节点为黑色时,此时不需要做额外处理

p节点为红色时(由于不能有连续红色节点,g节点必定黑色)需要额外讨论以下几种情况

  1. 当u节点存在且为红色时
  2. 当u节点不存在或存在且为黑色时(此种情况处理相同)

 注:

对于根节点为空或p节点为黑色时,较为简单,不做讨论,对剩余几种情况特殊分析。需要注意的是,以下分析的情况均是p节点为g节点的左孩子节点的情况,对于p为g的右孩子节点的情况处理逻辑是一样的。

1.p为红色,u为红色(不需要旋转操作)

对于p节点,u节点都为红色的情况,我们需要将p、u两个节点都变为黑树,将g节点变为红色

这样可以确保p、u以下的节点各个路径的黑树节点数量是一致的,但是由于g节点的颜色发生了变化,这可能导致g节点的颜色违反了红黑树的条件约束(不能有连续的红色节点),因为我们并不知道p的上一节点的颜色究竟是红色还是黑色,所以需要对从g节点继续往上调整及节点颜色,只需要将cur改变为指向g节点即可,让其继续循环调整。

 2.p为红色,u为黑色or不存在(需要旋转操作)

 对于p节点为红色,u节点为黑树或不存在时,需要通过旋转的操作来调整树高,而由于cur节点的左右位置对旋转的操作又有着不同的情况,这需要分两种情况,当cur节点的左右位置与p节点相同时(指节点cur、p同时为左节点或右节点),此时只需要1次旋转操作+调色即可当cur节点左右位置与p节点不同时需要使用额外1次旋转操作来使得cur、p节点的左右位置相同,变为只需要旋转1次的情况

 这里红黑树的旋转与AVL树的旋转操作是完全一致的,例如上图图是较为复杂的一种情况,cur、p节点左右位置不同,此时旋转调整节点为p节点,与AVL树中的旋转调整节点相同,下图所对应的是左旋的操作,通过将cur替代p节点的位置,然后将cur的左子树链接到p节点的右节点,p节点再链接到cur的左子树上,完成左旋转的操作。

通过旋转的操作使得cur、p节点的左右位置相同后,我们还需要做一个额外处理:通过交换cur以及p节点处的指针所指向的节点(为了使得此次旋转过后情况与只需要旋转1次的情况完全相同,使得cur、p的位置变为我们熟悉的位置,如下图的cur、p左右位置相同的情况,此时再对g节点旋转一次(右旋),将p节点替代g的位置,p的右子树链接到g的左子树上,再将g连接到p的右子树上,最好通过调色,将p节点颜色变为红色p节点变为黑色,即完成了对红黑树的调整。

有关红黑树数据插入的总结 

由于红黑树旋转的操作与AVL树中的旋转是一模一样的,所以在这里并没有过多讲解,而对于另一种p节点位于右子树的情况处理逻辑是一样的,可以画图捋一下这另一种情况。

红黑树的数据插入的操作是十分复杂的,需要我们仔细理解,通过多画图我们才能够更好去理解,只有动手画图尝试自己去理解才能够更好的了解红黑树对于数据插入的这一过程。

4红黑树与AVL树

提到红黑树,难免会让人想到AVL树,两数十分相似,但是红黑树的出现却基本取代了AVL树,相比于ALV树,虽然红黑树的查找数据的效率可能略低一点(实际差距不大),但是红黑树对于修改数据的效率要更加高效。 

红黑树的底层实现逻辑大致与AVL树是相同的,都是通过子树的旋转来控制两侧树高,但不同于AVL树,AVL树是一颗十分严格的平衡二叉搜索树,其子树的高度差都不能超过2,也正是因为这种严格的平衡要求,使得AVL树的对于数据的修改需要通过大量的旋转操作来完成,从而降低了AVL树的效率,而红黑树对于树高的控制显得更加不那么严格,红黑树中的左树树高只要满足一侧树高不超过另一侧的两倍即可。

总得来说,相比于AVL树,红黑树除了查找的效率略低,对于数据的删除插入等修改操作是更加高效的,而红黑树之所以能够取代AVL树也主要是由于对数据的修改效率高,更加全能。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

wpa_cli支持EAP-TLS认证运行设计

wpa_cli支持EAP-TLS认证运行设计 1 输入 1.1启动wpa_supplicant 和 wpa_cli 在OpenHarmony开发板或华为开发机的命令行中输入 wpa_supplicant -Dnl80211 -c/data/service/el1/public/wifi/wpa_supplicant/wpa_supplicant.conf -gabstract:/data/service/el1/public/wifi/sock…

物联网行业中3D打印工艺——FDM(熔融沉积成型技术)工艺

01 3D打印工艺——FDM工艺简介 格融沉积快速成型(Fused Deposion Modeling, FDM)是继光固化快速成型和叠层实体快速成型工艺后的另一种应用比较广泛的快速成型工艺。该技术是当前应用较为广泛的一种3D打印技术&#xff0c;同时也是最早开源的3D打印技术之一。该工艺方法以美国…

农场小程序带你走进生态农产品的世界

在快节奏的现代生活中&#xff0c;人们对食品安全的关注日益增强&#xff0c;对环境、健康农产品的需求也愈发迫切。然而&#xff0c;传统农产品市场往往信息不透明&#xff0c;消费者难以直接了解农产品的生长环境和生产过程&#xff0c;导致信任缺失。而农场小程序的出现&…

制定六西格玛人才培养方案需要考虑哪些因素?

当下&#xff0c;六西格玛作为一种先进的质量管理方法&#xff0c;被越来越多的企业采纳并应用于日常管理和流程优化中。然而&#xff0c;要成功实施六西格玛&#xff0c;关键在于培养一支具备高度专业素养和实战能力的六西格玛人才队伍。那么&#xff0c;制定六西格玛人才培养…

什么情况?上交所服务器被你们给买崩了?

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 上午好&#xff0c;我的网工朋友。 9月27日早上&#xff0c;A股市场迎来了一波前所未有的火爆行情&#xff0c;成交量激增&#xff0c;市场情绪高…

加固与脱壳03 - 加固技术讨论

在 02 中&#xff0c;贴了一张图&#xff0c;里面涵盖了加固的绝大部分知识。现在我们稍微展开说一下其中几个&#xff0c;也是后续会深入学习的&#xff0c;其中一些还需要单独成系列才行。 代码混淆 分为 Java 层与 Native 层混淆。 Java 层的混淆主要分为两种&#xff1a…

基于微信小程序的交友平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

[ComfyUI]Flux:超美3D微观山水禅意,经典中文元素AI重现,佛陀楼阁山水画卷

在数字艺术和创意领域&#xff0c;[ComfyUI]Flux以其独特的虚实结合技术&#xff0c;已经成为艺术家和设计师们手中的利器。今天&#xff0c;我们激动地宣布&#xff0c;[ComfyUI]Flux带来了一款超美的3D微观山水禅意作品&#xff0c;经典中文元素通过AI技术重现&#xff0c;包…

结婚证识别-离婚证识别接口-结婚证识别API应用场景

在信息化与智能化高速发展的今天&#xff0c;证件的自动识别技术逐渐成为了各行各业数字化转型的关键工具&#xff0c;而结婚证识别接口、离婚证识别接口正在悄然改变着传统的民政工作方式。 结婚证识别与离婚证识别接口是基于光学字符识别&#xff08;OCR&#xff09;技术的智…

热门财务软件大盘点,哪款最适合你?

本文介绍了ZohoBooks、金蝶云、速达会计等10款财务记账软件&#xff0c;各具优点&#xff0c;适合不同需求企业。各软件特点包括实时财务跟踪、多币种管理、无缝银行账户同步等&#xff0c;助企业高效管理财务。建议企业根据自身需求试用后选择。 一、Zoho Books Zoho Books是…

FreeRTOS列表与列表项

1.什么是列表与列表项 列表与列表项实际上是FreeRTOS中一个大量使用的一种数据结构 1.列表 列表的概念有点像链表&#xff0c;在 FreeRTOS 中&#xff0c;列表主要用于以下几个方面&#xff1a; 任务的管理&#xff1a;FreeRTOS 使用列表来管理不同的任务&#xff0c;包括就…

计算机网络面试题——第二篇

1. TCP拆包和粘包 现象 粘包&#xff1a;指在TCP传输中&#xff0c;发送方的多个数据包在接收方被合并在一个包接收&#xff0c;导致多条消息数据粘在一起&#xff0c;接收方无法正确区分这些消息的边界。拆包&#xff1a;指的是发送方的一个数据包在接收方被分成了多个包接收…

springboot集成mybatis插入数据时返回刚插入数据的自增id,插入数据没有使用实体

直接上代码吧 需要改两个地方一个dao一个xml 实现类里的逻辑 dao中新增注解 Options(useGeneratedKeys true, keyProperty "id")xml中新增 useGeneratedKeys"true" keyProperty"id"

2024年【电工(高级)】考试题及电工(高级)考试内容

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 电工&#xff08;高级&#xff09;考试题根据新电工&#xff08;高级&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将电工&#xff08;高级&#xff09;模拟考试试题进行汇编&#xff0c;组成一套电工…

Android问题笔记五十:构建错误-AAPT2 aapt2-7.0.2-7396180-windows Daemon

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

xxl-job--03--分片广播 动态分片

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 xxl-job通过分片广播模式前言1.定义什么是分片广播&#xff1a;即xxl-job调度中心发出一次调度&#xff0c;所有相关节点全部执行一次 采用分片广播调度优点 2.API介…

基于 ESP-AT 固件从外部服务器获取文件,使用分段续传的方式

**可使用 ATHTTPCGET 指令获取 HTTP\HTTPS 的资源&#xff0c;将返回资源的 Size 和 Data ** AT 指令序列如下&#xff1a; ATRESTOREATCWMODE1 //设置 WiFi Station 模式ATCWJAP"cc2.4","12345678" //连接 WiFi ATHTTPCHEAD…

JAVA全球美业新风尚国际版同城美容美发到店上门一体化服务系统小程序源码

全球美业新风尚&#xff0c;美丽触手可及&#xff01;✨ &#x1f30d; 开篇&#xff1a;引领国际美业新潮流 在这个追求个性与美丽的时代&#xff0c;美容美发已不再是简单的日常护理&#xff0c;它成为了我们展现自我、追求品质生活的一种方式。而“全球美业新风尚国际版同…

qt 图形视图框架 事件处理

Qt 的图形视图框架&#xff08;Graphics View Framework&#xff09;提供了一套丰富的类来管理大量的自定义 2D 图形项&#xff08;QGraphicsItem&#xff09;&#xff0c;以及这些图形项之间的交互和事件处理。在这个框架中&#xff0c;事件处理是一个关键部分&#xff0c;它允…

如意控物联网项目-ML307R模组软件及硬件调试环境搭建

软件及硬件调试环境搭建 1、 软件环境搭建及编译 a) 打开官方SDK&#xff0c;内涵APP-DEMO&#xff0c;通过vscode打开程序&#xff0c; 软件程序编写及编译参考下边说明文档链接 OneMO线上服务平台 编译需预安装python3.7以上版本&#xff0c;安装完python后&#xff0c;打开…