【C++】红黑树模拟实现插入功能(包含旋转和变色)

红黑树模拟实现并封装为map和set

  • 前言
  • 正式开始
    • 红黑树概念
    • 红黑树基本要求
    • 大致框架
      • 树节点
    • 调整红黑树使其平衡
      • 第一种:cur红,p红,g黑,u存在且为红
      • 第二种:cur红,p红,g黑,u不存在或为黑
        • 左左,右右:单旋 + 变色
        • 左右,右左:双旋 + 变色

在这里插入图片描述

前言

本篇主要讲解红黑树的模拟实现,实现之后再封装成map和set。

红黑树中所用到的旋转功能均源自我的上一篇博客,本篇中不会再详谈旋转,若对于旋转不了解的同学可以先看看上一篇博客:【C++】AVL树模拟实现插入功能

正式开始

前一篇的AVL树,是严格平衡的一棵二叉搜索树,也就是每个节点的做右子树高度差不超过1。

红黑树,在二叉搜索树的基础上,多了一个条件:最长路径不超过最短路径的2倍。没有AVL树那么严格,但是也是近似平衡的。

同AVL树相比,插入同样的数据,AVL树旋转更多,红黑树旋转更少,红黑树的优势就在于此,这一点比AVL树优很多,毕竟每次旋转的时候还是要动不少指针的。

但同时红黑树也有一丁点的劣势,查找效率比AVL树低一丢丢,因为极端情况下,也就是最长路径就是最短路径的2倍时,当我们正好要查找最长路径的叶子节点时,速度比AVL树慢了一半。但是虽说是一半,那也只是 l o g 2 N log_2N log2N的一半,如果存储10亿个数,查找最边上的节点,也就查找30次就能找到,因为对于AVL树来说几乎是完全二分的,那么红黑树的最坏情况就是60次喽,但是这样二者相差可以说是忽略不计的。

所以考虑整体情况的话,还是红黑树更胜一筹。不然STL中的map和set底层用的就不是红黑树了。

红黑树概念

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

先来一棵树看看:
在这里插入图片描述

看起来花里胡哨的,不要怕,纸老虎。

红黑树基本要求

红黑树实现的时候不是按照AVL树那样依靠平衡因子来实现的。而是通过控制节点是红色还是黑色来实现的,不然也就不叫红黑树了。

但是对于节点是红色还是黑色是有要求的:

  1. 每个节点非黑即红
  2. 根节点是黑色的
  3. 红色节点的两个子节点为黑色的,即树中没有连续的红色结点
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点。即每条路径上黑色结点数相等。
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)。

第五点其实没什么用,是指空节点是黑色节点,当树是空树的时候正好可以和第二条对应。树是空树,根节点就是空的,空节点是黑色节点,那么根节点也就是黑色结点了。

我再把上面那张图拿出来,各位对着前四点看看:
在这里插入图片描述

每个结点满足上述条件后就能够保证最长路径不超过最短路径的二倍了。各位想想为什么。

上述条件中可没有说不能有连续的黑色节点,所以最短路径就可以是连续黑色结点所组成的路径,最长路径就是一黑一红一黑一红…组成的路径。那么当到达极限时,最长路径就正好是最短路径的二倍。

再问个问题:
上图中,一共有几条路径?

答案是:11条。
有的同学可能懵了,不要懵。
上面数路径是要数到空节点的,上面一共有11个空节点,所以也就是11条路径。
这里也是第五点的一个好处,方便我们数路径,可以看到图中空节点写的是NIL,红黑树这里把空节点叫做NIL节点。

废话不多说了,我们先把树大致框架搞出来。

大致框架

树节点

红黑树树节点中包含的东西如下:
在这里插入图片描述

构造函数为:
在这里插入图片描述
颜色暂时不给,等会插入的时候会再说。

再来写树。

初始就一根:
在这里插入图片描述

然后把二叉搜索树的基本的插入功能写出来:
在这里插入图片描述

上面我把调整树结构的留下,这里细讲。

调整红黑树使其平衡

若插入新节点后的树结构不符合了前面说的那四条规则,此时就要调整。

但是插入节点要确定一下其颜色,如何确定呢?
看第三条和第四条规定。不能有连续的红色节点,所有路径黑色节点数量相同。

所以如果我们插入红色节点,影响的就只是当前插入节点所处的路径,因为红色节点不相连即可。如果我们插入黑色结点,影响的就是整棵树了,因为当前路径加一个黑的,其他路径就都要加一个黑的。显然,我们要选就选红色的插入,千万不敢选黑色的插,一选黑色就要调整棵树,选了红色只调当前路径就够了。

那么调整之前,我得先声明几个节点的名字

  1. cur节点,就是新插入的节点,等会在调整的过程中我以cur表示。
  2. . 父(father)节点 / 双亲(parent)节点, 等会在调整的过程中我以字母p表示。
  3. 叔叔(uncle)节点,就是父节点的兄弟,等会在调整的过程中我以字母u表示。
  4. 爷爷(grandfather)节点,就是父节点的父节点,等会在调整的过程中我以字母g表示。

先来个图看看:
在这里插入图片描述

那么调整可分为两大种情况。

第一种:cur红,p红,g黑,u存在且为红

第二种:cur红,p红,g黑,u不存在或为黑

说一下为啥是上面两种。
首先我们插入的一定是红色节点。

  1. 树为空的时候,不需要调整,直接让根搞成黑色节点。
  2. 插入节点为红色,p为黑色,此时不需要调整,直接插入即可。因为前面也说了,极限长度是黑红黑红这样规律走下去的,当插入的是红色的时候,不会出现到达最长路径的情况。所以不需要调整。
  3. 插入节点为红色,p为红色,违反第三条规定,此时就需要调整。而且当p为红色的时候,g一定为黑色,因为原树要保证是红黑树,所以当p是红色的时候,不能有连续的红色节点,所以g就一定是黑色的。

然后将第三点的调整分为两大种,至于为什么,等会将调整的时候就知道了,这是前人总结出来的规律。

那么就开始将调整。
如果你对于AVL树插入时的旋转非常熟悉了,那么这里红黑树插入的调整自然也不在话下。

正式开始调整:

第一种:cur红,p红,g黑,u存在且为红

调整方式为:pu变黑g变红,cur指向g继续向上调整,遇到树根为止,将树根改为黑。
即只有变色。

先来两个例子:

调整一次:
在这里插入图片描述

调整两次:
在这里插入图片描述

不用往下画了,再往下就是调整三、四、五……等等次数了。是有规律的,上面两个都是具象图,下来我把抽象图给大家,各位参考参考:
在这里插入图片描述

附上我手画的图:
在这里插入图片描述
比较潦草,主要是方便我看一下。

这里不管cur在p左边还是右边,调整方式都是一样的,记住最开始写的调整方式就行:

调整方式为:pu变黑g变红,cur指向g继续向上调整,遇到树根为止,将树根改为黑。
即只有变色。

第二种:cur红,p红,g黑,u不存在或为黑

第二大种就要用到旋转了,但还要再分为两小种。

第一小种:p在g左且cur在p左,或者p在g右且cur在p右。此种情况下为单旋。
对应的图为:
在这里插入图片描述
在这里插入图片描述

第二小种:p在g左且cur在p右,或者p在g右且cur在p左。此种情况下为双旋。
对应图为:
在这里插入图片描述
在这里插入图片描述

然后再细谈:

左左,右右:单旋 + 变色

单旋 + 变色。
和AVL树一样,左左就右单旋,右右就左单旋。

我就只画左左的,还是先给两个实例的图,再给抽象图。

在这里插入图片描述
在这里插入图片描述

抽象图:
在这里插入图片描述

左右,右左:双旋 + 变色

单旋 + 变色。
和AVL树一样,左右就左右双旋,右左就右左双旋。

实例:
在这里插入图片描述
在这里插入图片描述

抽象图:
在这里插入图片描述

手画图:
在这里插入图片描述

总结一下:
红黑树调节平衡关键是看叔叔。
u存在且为红,变色继续往上处理。
u不存在 或者 存在且为黑,旋转+变色。其中旋转又分单旋和双旋,若p、cur在单侧,就单旋,若p、cur一左一右或一右一左就双旋。

上面的三种情况搞完就可以写代码了。

调节平衡的代码如下:
在这里插入图片描述

其中我光用了单旋,没有用双旋,因为双旋就是两个单旋。
单旋代码:
在这里插入图片描述

可以写一个中序遍历来简单打印一下结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

但是简单的中序遍历可不够,来写一个专门用来检查是否平衡的函数。

在这里插入图片描述

在这里插入图片描述

到此结束。。。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实验记录——TT

8月份的小小实验 安装虚拟环境下载相关软件功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注释也…

视频汇聚平台EasyCVR安防监控视频汇聚平台的FLV视频流在VLC中无法播放的问题解决方案

众所周知,TSINGSEE青犀视频汇聚平台EasyCVR可支持多协议方式接入,包括主流标准协议国标GB28181、RTSP/Onvif、RTMP等,以及厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。在视频流的处理与分发上,视频监控…

Win10启动Jmeter报错提示jmeter.log拒绝访问问题

jmeter版本:5.4.1 查看版本 在dos命令窗口中进入jmeter安装目录下的bin目录中:执行jmeter - v命令 我启动的方式是:进入jmeter安装目录下的bin目录中双击jmeter.bat启动的。结果报错,但是不影响使用。 报错日志如下: …

【springmvc系】利用RequestBodyAdviceAdapter做接口鉴权

需求 有个简单的需求,对于第三方接口我们需要做个简单的鉴权机制,这边使用的是非对称性加密的机制。我们提供三方公钥,他们通过公钥对接口json报文使用加密后的报文请求,我们通过对接收过来的请求某一个加密报文字段来进行RSA解密…

学习笔记十四:K8S最小调度单元POD概述

K8S最小调度单元POD概述 k8s核心资源Pod介绍Pod是什么Pod如何管理多个容器Pod网络Pod存储代码自动发版更新收集业务日志 Pod工作方式自主式Pod控制器管理的Pod(防误删除) 如何基于Pod运行应用 k8s核心资源Pod介绍 K8s官方文档:https://kubernetes.io/ K8s中文官方文…

linux系统虚拟主机开启支持SourceGuardian(sg11)加密组件

注意:sg11我司只支持linux系统虚拟主机自主安装。支持php5.3及以上版本。 1、登陆主机控制面板,找到【远程文件下载】这个功能。 2、远程下载文件填写http://download.myhostadmin.net/vps/sg11_for_linux.zip 下载保存的路径填写/others/ 3、点击控制…

浅析前端请求登录与后台对接

首先确保前后端接口参数一致,我这里使用的是ant design Pro 前端框架 小技:shiftf6,全局重构,当接口不一致时很方便 前: 后: 前后端交互:前端需要向后端发送请求,前端ajax来请求后…

测试相关Liunx基础知识

Linux的历史和安装 基本常识 Liunx目录结果 常见

瑞数信息《2023 API安全趋势报告》重磅发布: API攻击持续走高,Bots武器更聪明

如今API作为连接服务和传输数据的重要通道,已成为数字时代的新型基础设施,但随之而来的安全问题也日益凸显。为了让各个行业更好地应对API安全威胁挑战,瑞数信息作为国内首批具备“云原生API安全能力”认证的专业厂商,近年来持续输…

Spring Profile与PropertyPlaceholderConfigurer实现项目多环境配置切换

最近考虑项目在不同环境下配置的切换,使用profile注解搭配PropertyPlaceholderConfigurer实现对配置文件的切换,简单写了个demo记录下实现。 基本知识介绍 Profile Profile通过对bean进行修饰,来限定spring在bean管理时的初始化情况&#…

AssetBundle总结

文章目录 目的打包过程打包时的分组策略和压缩方式资源的载入和卸载其它:Manifest、校验、视图工具思维导图 前言: 大佬文章链接(据此总结的) 目的 避免软件因资源占用空间太大,导致运行缓慢 避免每次更新资源&#…

区块链世界的大数据入门之zkMapReduce简介

1. 引言 跨链互操作性的未来将围绕多链dapp之间的动态和数据丰富的关系构建。Lagrange Labs 正在构建粘合剂,以帮助安全地扩展基于零知识证明的互操作性。 2. ZK大数据栈 Lagrange Labs 的ZK大数据栈 为一种专有的证明结构,用于在任意动态分布式计算的…

引入三阶失真的非线性放大器的模拟输出及使用中值滤波器去除峰值研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Jmeter快捷方式和应用图标设置

很多人在安装Jmeter,安装到本机却没有icon,每次使用的时候,每次打开应用都要找目录,不太方便。 【解决问题】 使用bin路径下的一个.bat文件,创建快捷方式。 【操作步骤】 Step1、将Jmeter 安装bin路径下的jmeter.bat 发送快捷方…

[MAUI]在.NET MAUI中实现可拖拽排序列表

.NET MAUI 中提供了拖放(drag-drop)手势识别器,允许用户通过拖动手势来移动控件。在这篇文章中,我们将学习如何使用拖放手势识别器来实现可拖拽排序列表。在本例中,列表中显示不同大小的磁贴(Tile)并且可以拖拽排序。 …

mac arm 通过brew搭建 php+nginx+mysql+xdebug

1.安装nginx brew install nginx //安装brew services start nginx //启动2.安装php brew install php7.4 //安装export PATH"/opt/homebrew/opt/php7.4/bin:$PATH" //加入环境变量 export PATH"/opt/homebrew/opt/php7.4/sbin:$PATH"brew serv…

fiddler抓包工具的用法以及抓取手机报文定位bug

前言: fiddler抓包工具是日常测试中常用的一种bug定位工具 一 抓取https报文步骤 使用方法: 1 首先打开fiddler工具将证书导出 点击TOOLS------Options------Https-----Actions---选中第二个选项 2 把证书导出到桌面后 打开谷歌浏览器 设置---高级…

ROS2 学习(二)工作空间,节点

工作空间介绍 workspace 是存放整个项目的大目录。 其中包含: src:源码。 build:编译文件。 install:安装空间,存放编译成功后的目标文件。 log:日志。 我们新建一个工作空间目录,其中包…

转行软件测试四个月学习,第一次面试经过分享

我是去年上半年从销售行业转行到测试的,从销售公司辞职之后选择去培训班培训软件测试,经历了四个月左右的培训,在培训班结课前两周就开始投简历了,在结课的时候顺利拿到了offer。在新的公司从事软件测试工作已经将近半年有余&…

python3 0基础学习笔记

0基础学习笔记,临时有事暂停后边会继续学习 基础内容1. 条件语句 if - elif - else2. 错误铺捉try - except(一种保险策略)3. 四种开发模式4. 函数:def用来定义函数的5. 最大值最小值函数,max ,min6. is 严格的相等&am…