当前位置: 首页 > news >正文

【C++笔记】红黑树(RBTree)深度剖析和AVL树的对比分析

【C++笔记】红黑树(RBTree)深度剖析和AVL树的对比分析

在这里插入图片描述

🔥个人主页大白的编程日记

🔥专栏C++笔记


文章目录

  • 【C++笔记】红黑树(RBTree)深度剖析和AVL树的对比分析
    • 前言
    • 一.红黑树的定义
      • 1.1 红黑树的概念
      • 1.2红黑树的规则
      • 1.3 红黑树对比AVL树
    • 二.红黑树的插入
      • 2.1插入分析
      • 2.1变色
      • 2.2 旋转+变色
      • 2.3 代码实现
    • 三.红黑树的查找
    • 四.红黑树的验证
      • 4.1 思路分析
      • 4.2 代码实现
    • 后言

前言

哈喽,各位小伙伴大家好!上期我们讲了反向迭代器和计算器。今天我们来讲一下红黑树的深度剖析。话不多说,我们进入正题!向大厂冲锋
在这里插入图片描述

一.红黑树的定义

1.1 红黑树的概念

红黑树是⼀棵⼆叉搜索树,他的每个结点增加⼀个存储位来表示结点的颜色,可以是红色或者黑色。通过对任何⼀条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有⼀条路径会比其他路径长出2倍,因而是接近平衡的。

1.2红黑树的规则

  • 每个结点不是红色就是黑色

  • 根节点是黑色的

  • 如果⼀个结点是红色的,则它的两个孩子结点必须是黑色的,也就是说任意⼀条路径不会有连续的红色结点。

  • 对于任意⼀个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的黑色结点
    这些都是红黑树。

  • 说明:《算法导论》等书籍上补充了⼀条每个叶⼦结点(NIL)都是黑色的规则。他这里所指的叶子结点不是传统的意义上的叶子结点,而是我们说的空结点,有些书籍上也把NIL叫做外部结点。NIL是为了方便准确的标识出所有路径,《算法导论》在后续讲解实现的细节中也忽略了NIL结点,所以我们知道⼀下这个概念即可。
    =
    这棵树我们看可能以为是四条路径。

    但是其实他是八条路径。
    规定空节点是黑的符合红黑树的规则并且方便我们观察红黑树的路径。

由中这几点规则我们可以推出红黑树的性质:

  • 最长路径<=2*最短路径

1.3 红黑树对比AVL树

红黑树的性能不如AVL树因为他没有那么严格地控制高度差。但是他的性能也不会太差,因为他控制最长路径<=2*最短路径。所以他的性能还是在logN的量级

红黑树的表达相对AVL树要抽象⼀些,AVL树通过高度差直观的控制了平衡。红黑树通过4条规则的颜色约束,间接的实现了近似平衡,他们效率都是同⼀档次,但是相对而言,插入相同数量的结点,红黑树的旋转次数是更少的,因为他对平衡的控制没那么严格。

在这**加粗样式**里插入图片描述
总结:

  • 查找
    红黑树的性能稍逊一筹AVL树
    因为他的高度控制没那么严格但都是logN量级。

  • 插入
    红黑树的性能要比AVL树好
    虽然红黑树多了变色操作,但是变色操作简单,代价小。 并且红黑树高度控制没那么严格大量插入时旋转的调整次数比AVL树要少。所以插入是红黑树的性能更优秀。

二.红黑树的插入

2.1插入分析

  • 插入⼀个值按⼆叉搜索树规则进行插入,插入后我们只需要观察是否符合红黑树的4条规则。
  • 如果是空树插入,新增结点是黑色结点。如果是非空树插⼊,新增结点必须红色结点,因为非空树插入,新增黑色结点就破坏了规则4,规则4是很难维护的。
  • 非空树插入后,新增结点必须红色结点,如果父亲结点是黑色的,则没有违反任何规则,插⼊结束
  • 非空树插入后,新增结点必须红色结点,如果⽗亲结点是红⾊的,则违反规则3。进⼀步分析,c是红色,p为红,g必为黑,这三个颜色都固定了,关键的变化看u的情况,需要根据u分为以下几种情况分别处理。
    说明:下图中假设我们把新增结点标识为c (cur),c的父亲标识为p(parent),p的父亲标识为g(grandfather),p的兄弟标识为u(uncle)。

2.1变色

c为红,p为红,g为黑,u存在且为红,则将p和u变黑,g变红。在把g当做新的c,继续往上更新。

分析:因为p和u都是红色,g是黑色,把p和u变黑,左边子树路径各增加⼀个黑色结点,g再变红,相当于保持g所在子树的黑色结点的数量不变,同时解决了c和p连续红色结点的问题,需要继续往上更新是因为,g是红色,如果g的父亲还是红色,那么就还需要继续处理;如果g的父亲是黑色,则处理结束了;如果g就是整棵树的根,再把g变回黑色。

p是右子树也是一样的

所以p和cur在左还是在右我们并不关注。
只要u存在并且为红色我们都按照这种方式处理即可。

2.2 旋转+变色

如果u不存在或u存在为黑。
我们需要根据cur和p的位置分类讨论

  • 单旋

c为红,p为红,g为黑,u不存在或者u存在且为黑,u不存在,则c⼀定是新增结点,u存在且为黑,则c⼀定不是新增,c之前是黑色的,是在c的子树中插入,,变色将c从黑色变成红色,更新上来的。

分析:p必须变黑色,才能解决,连续红色结点的问题,u不存在或者是黑色的,这里单纯的变色无法解决问题,需要旋转+变色。

如果p是左子树并cur是左子树
在这里插入图片描述

如果p是g的左,c是p的左,那么以g为旋转点进行右单旋,再把p变黑,g变红即可。p变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为p的父亲是黑色还是红色或者空都不违反规则。

如果p是右子树并cur是右子树

如果p是g的右,c是p的右,那么以g为旋转点进行左单旋,再把p变黑,g变红即可。p变成课这颗树新的根,这样i树黑色结点的数量不变,没有连续的红结点了,且不需要往上更新,因为p的父亲是黑色还是红色或者空都不违反规则。

那就是以g进行左单旋 在把g变红 p变黑。

  • 双旋

如果p是左子树cur是右子树

如果p是g的左,c是p的右,那么先以p为旋转点进行左单旋,再以g为旋转点进行右单旋,再把c变黑,g变红即可。c变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为c的父亲是黑色还是红色或者空都不违反规则。

如果p是右子树cur是左子树

如果p是g的右,c是p的左,那么先以p为旋转点进行右单旋,再以g为旋转点进行左单旋,再把c变黑,g变红即可。c变成课这颗树新的根,这样子树黑色结点的数量不变,没有连续的红色结点了,且不需要往上更新,因为c的父亲是黑色还是红色或者空都不违反规则。

2.3 代码实现

bool Insert(const k& x, const v& v)
{if (_root == nullptr)//插入根节点{_root = new node(x, v);return true;}node* cur = _root;node* parent = nullptr;//保留父亲节点while (cur){/*介质不冗余*/if (x < cur->_key){parent = cur;cur = cur->left;}else if (x > cur->_key){parent = cur;cur = cur->right;}else{return false;}}cur = new node(x, v);cur->col = RED;if (x > parent->_key){parent->right = cur;}else//相等插入左子树{parent->left = cur;}cur->parent = parent;while (parent&&parent->parent&&parent->col == RED){node* grandfather = parent->parent;if (parent == grandfather->left){node* uncle = grandfather->right;//         g//       p    u//     c  c//u存在且为红if (uncle&&uncle->col==RED){parent->col = uncle->col=BLACK;grandfather->col = RED;cur = grandfather;parent = cur->parent;}//u不存在或存在为黑else{//         g//       p    //     cif (cur == parent->left){RoRateR(grandfather);parent->col = BLACK;grandfather->col = RED;}//         g//       p    //         celse{RoRateL(parent);RoRateR(grandfather);cur->col = BLACK;grandfather->col = RED;}break;}}else{node* uncle = grandfather->left;//         g//       u   p    //          c  c//u存在且为红if (uncle && uncle->col == RED){parent->col = uncle->col = BLACK;grandfather->col = RED;cur = grandfather;parent = cur->parent;}//u不存在或存在为黑else{//         g//            p    //              cif (cur == parent->right){RoRateL(grandfather);parent->col = BLACK;grandfather->col = RED;}//         g//            p    //          celse{RoRateR(parent);RoRateL(grandfather);cur->col = BLACK;grandfather->col = RED;}break;}}}_root->col = BLACK;//循环结束把根变黑return true;
}

三.红黑树的查找

红黑树的查找和AVL树的规则一样。
对比根节点和目标值的大小再取左子树或右子树查找。

node* Find(const k& x)
{node* ret = nullptr;node* cur = _root;while (cur){if (x < cur->_key){cur = cur->left;}else if (x > cur->_key){cur = cur->right;}else{ret = cur;//保留当前节点cur = cur->left;//继续向左子树查找中序的第一个}}return ret;
}

四.红黑树的验证

4.1 思路分析

我们检查红黑树主要检查是否满足红黑树的规则即可。

4.2 代码实现


bool check(node* cur,size_t tmp,size_t sum)
{if (cur == nullptr){if (tmp != sum){cout << "存在⿊⾊结点的数量不相等的路径" << endl;return false;}return true;}if (cur->col == RED){if (cur->parent->col == RED){cout << cur->_key << ":" << "存在连续红节点" << endl;return false;}}else{sum++;}return check(cur->left, tmp, sum) && check(cur->right, tmp, sum);
}
bool ISRBTree()
{return _ISRBTree(_root);
}
bool _ISRBTree(node* cur)
{if (cur == nullptr){return true;}if (cur->col == RED){return false;}size_t t = 0;while (cur){if (cur->col == BLACK){t++;}cur = cur->left;}return check(_root,t,0);
}

这里我们通过几组数据来看一下AVL树和红黑树的性能。

void Test()
{const int N = 100000;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; i++){v.push_back(rand() + i);}size_t begin2 = clock();AVL::AVLTree<int, int> t;for (auto e : v){t.Insert(e, e);}size_t end2 = clock();size_t begin3 = clock();RBTree::RBTree<int, int> t1;for (auto e : v){t1.Insert(e, e);}size_t end3 = clock();size_t begin1 = clock();// 确定在的值/*for (auto e : v){t.Find(e);}*/// 随机值for (size_t i = 0; i < N; i++){t.Find((rand() + i));}size_t end1 = clock();size_t begin4 = clock();for (size_t i = 0; i < N; i++){t1.Find((rand() + i));}size_t end4 = clock();cout << "AVLInsert:" << end2 - begin2 << endl;cout << "AVLTree:"<<t.IsBalanceTree() << endl;cout << "AVLHeight:" << t.Height() << endl;cout << "AVLSize:" << t.Size() << endl;cout << "AVLFind:" << end1 - begin1 << endl;cout << "RBInsert:" << end3 - begin3 << endl;cout << "RBTree:" << t1.ISRBTree() << endl;cout << "RBHeight:" << t1.Height() << endl;cout << "RBSize:" << t1.Size() << endl;cout << "RBFind:" << end4 - begin4 << endl;
}
  • Debug
    10万数据
    在这里插入图片描述100万数据

    1000万数据
    在这里插入图片描述
  • Release
    10万数据

    100万数据

    1000万数据
    在这里插入图片描述

观察数据可以发现红黑树的查找比AVL要慢一些,
在release下查找效率都一样,因为CPU太快了。
但是红黑树在大量数据插入的情况下比AVL树要不少。

后言

这就是红黑树的深度剖析。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

相关文章:

【C++笔记】红黑树(RBTree)深度剖析和AVL树的对比分析

【C笔记】红黑树(RBTree)深度剖析和AVL树的对比分析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】红黑树(RBTree)深度剖析和AVL树的对比分析前言一.红黑树的定义1.1 红黑树的概念1.2红黑树的规则1.3 红黑树对比A…...

Pytorch初学

创建虚拟环境 python控制台&#xff0c;jupyter notebook,python文件运行的差异&#xff0c;后续结合使用三者。 jupter主要可以对代码进行分割单独运行&#xff0c;主要做一些探索性工作。 数据集的常见存储模式 1、以标签命名图像。 2、单独存储图像的地址。 加载数据集…...

Golang学习笔记_20——error

Golang学习笔记_17——方法 Golang学习笔记_18——接口 Golang学习笔记_19——Stringer 文章目录 error1. 接口2. 创建3. 自定义错误4. 处理错误5. 实现Error接口 源码 error 在Go语言中&#xff0c;error 是一个内建的接口类型&#xff0c;用于表示和处理错误情况。它是Go语言…...

基于Vite+TS初始项目 | 不断更新

1 创建项目 1.1 初始化项目 # 创建项目 pnpm create vite# 使用vue-ts模板创建项目 pnpm create vite xyz-vue-app-ts --template vue-ts1.2 添加ts类型检查命令 添加 "type-check" 类型检查命令 {"name": "xyz-vue-app-ts-test","scri…...

R语言装环境Gcc报错以及scater包的安装

error: ‘timespec_get’ has not been declared in ‘::’ 80 | using ::timespec_get; 在conda 的虚拟环境中升级gcc的版本 conda install -c conda-forge gcc11 gxx11终极方法&#xff0c;在R的最新版本和环境下装啥都能成功&#xff01;&#xff01; 比如beyondcell的方法…...

关于量子神经网络的思考

其实在写这篇文章之前想了很多&#xff0c;主要是想法太超前&#xff0c;有可能颠覆未来机器智能行业甚至是影响世界。 1、计算机的历史 计算机的历史可以追溯到20世纪中叶&#xff0c;最早的电子计算机如ENIAC和EDVAC采用了冯诺依曼架构&#xff08;John von Neumann Archit…...

注册中心如何选型?Eureka、Zookeeper、Nacos怎么选

这是小卷对分布式系统架构学习的第9篇文章&#xff0c;第8篇时只回答了注册中心的工作原理的内容&#xff0c;面试官的第二个问题还没回答&#xff0c;今天再来讲讲各个注册中心的原理&#xff0c;以及区别&#xff0c;最后如何进行选型 上一篇文章&#xff1a;如何设计一个注册…...

使用 Conda创建新的环境遇到的问题

下载速度很慢 1、更新 conda update -n base -c defaults conda2、清理缓存 conda clean --all解决方法 方法 1&#xff1a;关闭严格的渠道优先级 检查是否开启了严格渠道优先级&#xff1a; conda config --show channel_priority 如果返回 strict&#xff0c;说明启用了严…...

Flutter项目开发模版,开箱即用(Plus版本)

前言 当前案例 Flutter SDK版本&#xff1a;3.22.2 本文&#xff0c;是由这两篇文章 结合产出&#xff0c;所以非常建议大家&#xff0c;先看完这两篇&#xff1a; Flutter项目开发模版&#xff1a; 主要内容&#xff1a;MVVM设计模式及内存泄漏处理&#xff0c;涉及Model、…...

Spring Boot + Jasypt 实现application.yml 属性加密的快速示例

Jasypt(Java Simplified Encryption)是一个专为Java应用程序设计的开源加密库,旨在简化加密和解密流程,保护敏感数据如密码、API密钥等。 jasypt-spring-boot-starter允许开发者在Spring Boot应用中轻松地实现加密和解密功能。 本篇介绍使用 jasypt-spring-boot-starter 以…...

arcgisPro加载CGCS2000天地图后,如何转成米单位

1、导入加载的天地图影像服务&#xff0c;一开始是经纬度显示的。 2、右键地图&#xff0c;选择需要调整的投影坐标&#xff0c;这里选择坐标如下&#xff1a; 3、点击确定后&#xff0c;就可以调整成米单位的了。 4、切换后结果如下&#xff1a; 如有需要&#xff0c;可调整成…...

多模态论文笔记——GLIDE(DALL·E 2模型核心部件)

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍了OpenAI的DALLE 2模型中重要的组成部分&#xff0c;用于图像生成的GLIDE模型及其论文。 文章目录 论文背景扩散模型&#xff08;Diffusion Models&…...

mybatisPlus动态sql语句 ${ew.sqlSegment}

mybatis-plus的${ew.sqlSegment}&#xff0c;${ew.sqlSelect}&#xff0c;${ew.customSqlSegment} ew是mapper方法里的Param(Constants.WRAPPER) Wrapper queryWrapper对象 简答介绍&#xff1a; ${ew.sqlSelect}&#xff1a;拼接select SQL主体 Select("select ${ew.…...

【工具】HTML自动识别用户正在讲话 以及停止讲话

【工具】HTML自动识别用户正在讲话 以及停止讲话 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>语…...

小程序与内嵌网页的数据通信

小程序与内嵌网页的数据通信 前言 微信小程序提供了web-view组件&#xff0c;允许开发者在小程序中嵌入网页。然而&#xff0c;由于小程序和网页运行在不同的环境中&#xff0c;它们之间的通信就需要依赖特定的机制来实现。然而我们日常的需求中&#xff0c;很多的时候都涉及…...

Android - NDK:编译可执行程序在android设备上运行

在android开发中&#xff0c;调试时会把C代码直接编译成可执行程序&#xff0c;运行在android设备上以确认其功能是否正常。 1、基于NDK编译可执行文件 2、push到 /data/local/tmp目录下 3、设置权限&#xff0c;执行。 ndk工程中build.gradle设置 groovy plugins {id com.a…...

快速上手:采用Let‘sEncrypt免费SSL证书配置网站Https (示例环境:Centos7.9+Nginx+Let‘sEncrypt)

1 关于Let’s Encrypt与Cerbot DNS验证 Let’s Encrypt 是一个提供 免费证书 的 认证机构。 Cerbot 是 Let’s Encrypt 提供的一个工具&#xff0c;用于自动化生成、验证和续订证书。 DNS验证是 Cerbot 支持的验证方式之一。相比 HTTP 验证或 TLS-ALPN 验证&#xff0c;DNS …...

shell技能树-扩展变量

扩展变量是指在shell脚本中用于实现条件判断和变量操作的特殊语法。 表格总结&#xff1a; 前三个 存在或者非空时&#xff0c;优先使用待测变量&#xff0c;否则使用默认值&#xff08;或报错&#xff09;。 最后一个 存在或者非空时&#xff0c;优先使用默认值&#xff0c…...

基于RedHat9部署WordPress+WooCommerce架设购物网站

系统版本信息&#xff1a;Red Hat Enterprise Linux release 9.2 (Plow) WordPress版本信息&#xff1a;wordpress-6.6.2-zh_CN WooCommerce版本信息&#xff1a;woocommerce.9.5.1 环境架构&#xff1a;LNMP&#xff08;RedHat9nginx1.20.1PHP 8.0.27MySQL8.0.30&#xff09; …...

LabVIEW瞬变电磁接收系统

利用LabVIEW软件与USB4432采集卡开发瞬变电磁接收系统。系统通过改进硬件配置与软件编程&#xff0c;解决了传统仪器在信噪比低和抗干扰能力差的问题&#xff0c;实现了高精度的数据采集和处理&#xff0c;特别适用于地质勘探等领域。 ​ 项目背景&#xff1a; 瞬变电磁法是探…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...