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

C++模拟实现——红黑树

一、介绍

红黑树也是对一般的搜索二叉树不能保证平衡的一个改进,和AVL树采用的思路不同,但同样需要旋转,其本质也是一颗平衡搜索二叉树,其节点有颜色的区分,并且被一些规则束缚,在这些规则下,能够使得树最长路径的长度不会高于最短路径的两倍

二、红黑树的性质

1.红黑树的节点,不是红色,就是黑色

2.根节点是黑色的

3.路径上不能出现两个连续的红色节点

4.每条路径上的黑色节点数量相同

5.每个叶子节点指向的空节点,默认认为是黑色的

遵循以上规则,则可以保证最长的路径的长度不会超过最短路径的两倍,因此红黑树实现平衡的核心,就是对新插入的节点使其通过一系列操作,满足上面的五个条件即可

三、红黑树的定义

插入的节点默认为红色,是为了能够调整,插入红色,可能只需要局部调整,若是黑色,则每次插入都必然会影响所有路径

四、红黑树的核心实现Insert

1.基本框架

先是插入数据,然后再是根据规则做出调整,红黑树实现的核心就在于如何调整,使得各种情况的插入都可以调整成符合规则的样子

2.调整分析

情况一:当插入一个新的节点cur为根节点,则直接插入,并且将颜色改为黑色即可
(根节点为黑色)

情况二:继续插入,若是parent节点为黑色,则插入一个红色节点不会破坏规则,因此无需调整
(不能有连续的红色节点,每个路径黑色节点相同)

情况三:插入cur节点,其parent节点也是红色,则出现了两个连续的红色节点,需要根据不同情况进行分类调整:

(1).uncle存在且为红

处理:将parent和uncle变黑,将grandfather变红,然后继续向上调整,cur指向g
parent指向g->_parent

p和u同时变黑,使得g左右两边路径同时增加了一个黑色节点,因此需要将g变红,这样既不影响黑色节点的规则,也没有连续出现的红色节点,但是由于g变红,因此可能会对上面部分造成影响,所以需要继续向上调整,将cur指向grandfather,parent指向g的parent往上继续检查

(2)uncle不存在或者存在且为黑

处理:根据具体情况进行旋转(单旋、双旋),旋转后再将局部最上方的变黑,grandfather变红

旋转即降了高度,并且旋转后通过调整颜色,使得局部内同时符合黑色和红色的约束条件

需要特殊处理的就只有这两种情况,但在代码实现的角度,需要对这两种情况进行细分,首先是先判断parent在grandfather的左边还是右边,这个影响着旋转往哪边旋,然后再是分“叔叔存在且为红”和“叔叔不在或者在且为黑”这两种情况分类讨论,但是处理的思路是一样的,只是在细节上要根据具体情况进行调整,在“叔叔不在或者在且为黑”的条件下,需要继续细分cur在parent的左边还是右边,确定具体是单旋还是双旋,旋转后再变色即可

3.代码实现部分分析

4.具体代码

	bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (data < cur->_data){parent = cur;cur = cur->_left;}else if (data > cur->_data){parent = cur;cur = cur->_right;}else if (data == cur->_data){return false;}}cur = new Node(data);if (data < parent->_data){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//插入完成后检查是否需要调整while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (grandfather->_left == parent)//情况一,叔叔存在且为红{Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = grandfather->_parent;}else//叔叔不存在或者存在为黑{if (parent->_left == cur)//情况二{RotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else//情况三{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else//grandfather->right == parent{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = grandfather->_parent;}else{if (parent->_right == cur)//情况二{RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}//调整完后,将根重新置为黑色,避免某次调整到根时,将根变成了红色_root->_col = BLACK;return true;}

五、测试接口

在实现完Insert接口后,我们需要实现一些用于测试的接口,验证是否为红黑树

中序遍历InOrder

首先是提供一个中序遍历,但中序遍历只能验证是否是搜索二叉树,并不能保证一定是红黑树

	void InOrder(){_InOrder(_root);cout << endl;}void _InOrder(const Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_data << " ";_InOrder(root->_right);}

验证红黑树IsBalance

验证是否是红黑树,取决于树是否遵循着红黑树的规则,因此我们需要根据规则去写个函数去检查树是否为红黑树

	//测试是否为红黑树bool IsBalance(){if (_root->_col == RED){return false;}int Reference = -1;return _Check(_root,0,Reference);}//1.不能有连续的红色节点//2.每条路径的黑色节点要数量相同bool _Check(const Node* root,int black_num,int& Reference){if (root == nullptr){if (Reference == -1)//由第一次走完的路径作为参考值{Reference = black_num;}else if (Reference != black_num)//当存在黑色节点数量与参考值不同的路径时,说明违反规则{return false;}return true;}//当如果节点为红,则检查父母节点是否也为红,若是红则违反规则if (root->_col == RED && root->_parent && root->_parent->_col == RED){return false;}//统计每条路径的黑色节点,当走到空时则说明该路径走完if (root->_col == BLACK){black_num++;}return _Check(root->_left,black_num,Reference) && _Check(root->_right,black_num,Reference);}};

总结

本章模拟实现了红黑树的核心部分,提供了测试接口,下一篇将会把红黑树进行一些改造,并且完整红黑树的部分基本接口,用于封装set和map,并且将模拟实现对set和map的封装

相关文章:

C++模拟实现——红黑树

一、介绍 红黑树也是对一般的搜索二叉树不能保证平衡的一个改进&#xff0c;和AVL树采用的思路不同&#xff0c;但同样需要旋转&#xff0c;其本质也是一颗平衡搜索二叉树&#xff0c;其节点有颜色的区分&#xff0c;并且被一些规则束缚&#xff0c;在这些规则下&#xff0c;能…...

java基础-数据类型

1、变量 变量就是申请内存来存储值。也就是说&#xff0c;当创建变量的时候&#xff0c;需要在内存中申请空间。 内存管理系统根据变量的类型为变量分配存储空间&#xff0c;分配的空间只能用来储存该类型数据。 因此&#xff0c;通过定义不同类型的变量&#xff0c;可以在内…...

设计数据库的时候会考虑哪些因素,怎样去建表?

在设计数据库时&#xff0c;通常会考虑以下因素&#xff1a; 数据的结构和关系&#xff1a;首先需要分析业务需求&#xff0c;了解需要存储的数据类型、数据之间的关系以及数据的组织结构。 数据的完整性和一致性&#xff1a;确保数据库中的数据完整性和一致性&#xff0c;例如…...

AI 绘画 | Stable Diffusion精确控制ControlNet扩展插件

ControlNet ControlNet是一个用于控制AI图像生成的插件,通过使用Conditional Generative Adversarial Networks(条件生成对抗网络)的技术来生成图像。它允许用户对生成的图像进行更精细的控制,从而在许多应用场景中非常有用,例如计算机视觉、艺术设计、虚拟现实等。 对于…...

青少年编程学习 等级考试 信奥赛NOI/蓝桥杯/NOC/GESP等比赛资料合集

一、博主愚见 在当今信息技术高速发展的时代&#xff0c;编程已经成为了一种必备的技能。随着社会对于科技人才的需求不断增加&#xff0c;青少年编程学习正逐渐成为一种趋势。为了更好地帮助青少年学习编程&#xff0c;提升他们的技能和素质&#xff0c;博主结合自身多年从事青…...

Linux 函数库

函数库&#xff1a; 我们的C程序中&#xff0c;并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢? 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去…...

Java 入门基础题

目录 1.输出一个整数的每一位 2.判定素数 3.求最大值方法的重载 4.输出闰年 5.打印 X 图形 6.数字9 出现的次数 7.计算分数的值 8. 模拟登陆 9.使用函数求最大值 10.斐波那契数列 星光不负赶路人&#xff0c;加油铁子们&#xff01;&#xff01;&#xff01; 1…...

块设备的工作模式

块设备的mknod 还是会创建在 /dev 路径下面&#xff0c;这一点和字符设备一样。/dev 路径下面是 devtmpfs 文件系统。这是块设备遇到的第一个文件系统。我们会为这个块设备文件&#xff0c;分配一个特殊的 inode&#xff0c;这一点和字符设备也是一样的。只不过字符设备走 S_IS…...

Spring核心

Spring Framework Spring的两个核心IOC控制反转IOC容器依赖注入DIIOC容器实现注解管理BeanBean对象定义Bean对象获取 AOP面向切面编程 添加依赖入门案例注解通过Spring创建Java bean对象 xml管理Bean案例main下创建bean.XMl文件 DI依赖注入案例创建Spring配置文件 bean-di.xml …...

ffmpeg命令行处理视频,学习记录

ffmpeg命令行处理视频 截取视频前5s ffmpeg -ss 00:00:00 -t 00:00:05 -i .\public\uploads\20231109\116a292eccf8315f65d7166e794d1730.mp4 .\public\uploads\20231109\116a292eccf8315f65d7166e794d1731.mp4两视频合并为1个 ffmpeg -i F:\xuejiao\code\cms.openlai.com\p…...

Linux应用层点亮硬件的LED灯

一 应用层操作硬件的两种方法 应用层想要对底层硬件进行操控&#xff0c;通常可以通过两种方式&#xff1a; /dev/目录下的设备文件&#xff08;设备节点&#xff09;&#xff1b;/sys/目录下设备的属性文件。 具体使用哪种方式需要根据不同功能类型设备进行选择&#xff0c;通…...

密钥安全存储方案探讨与实践

随着信息技术的迅猛发展和应用范围的不断扩大&#xff0c;我们日常生活中的许多方面已经与信息技术密不可分。而在信息安全领域中&#xff0c;密钥的安全存储显得尤为重要。本文将探讨密钥安全存储的必要性、相关技术和实践方案&#xff0c;并提出一些解决方案。 一、密钥安全存…...

[pytorch]设备选择以及卷积神经网络的应用

0.写在前面: 首先这篇文章还没写完,因为今天要尝试对我之前的一个框架做一个简单的更新迭代,所以目前先更新这么多. 1.关于设备的选择 首先,目前的大多数电脑都是自带一些GPU(图形计算单元,在这里被称之为cuda), 需要安装相关的驱动才能正常使用这些设备和调用他们的具体情况…...

API SIX系列-服务搭建(一)

APIsix简介 APISIX是一个微服务API网关&#xff0c;具有高性能、可扩展性等优点。它基于nginx&#xff08;openresty&#xff09;、Lua、etcd实现功能&#xff0c;借鉴了Kong的思路。和传统的API网关相比&#xff0c;APISIX具有较高的性能和较低的资源消耗&#xff0c;并且具有…...

hadoop 大数据环境配置 同步时间 centos服务器时间同步 linux 安装ntp服务更新时间 hadoop(六)

1. 安装ntp软件 yum install -y ntp 2.创建软连接 # 删除之前得时间 sudo rm -rf /etc/localtime;# 更新时区sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime3. 更新时间 # root 权限运行 sudo ntpdate -u ntp.aliyun.com 4. 开机自启&#xff0c;更新时间 …...

基于单片机智能输液器监控系统的设计

**单片机设计介绍&#xff0c; 基于单片机智能输液器监控系统的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的智能输液器监控系统可以实现对输液过程的实时监测和控制&#xff0c;以下是一个基本的设计介绍&am…...

Unity解决:没有UnityWebRequest.Result

当我在Unity 2019中使用Unity 2021的代码satable时。 控制台显示 “UnityWebRequest”不包含“result”的定义,并且找不到接受“UnityWebRequest”类型的第一个参数的可访问扩展方法“result”(是否缺少using指令或程序集引用?) 漏洞/问题: if (req.result == UnityWebRe…...

记录Linux的Bug

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 例如&#xff1a;项目场景&#xff1a;示例:通过蓝牙芯片(HC-05)与手机 APP 通信&#xff0c;每隔 5s 传输一批传感器数据(不是很大) 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1…...

优化改进YOLOv5算法之感受野注意力卷积运算(RFAConv),效果秒杀CBAM和CA等

目录 1 RFAConv原理 1.1 回顾标准卷积 1.2 回顾空间注意力 1.4 创新空间注意力与标准卷积...

【设计原则篇】聊聊里氏替换原则

是什么 子类对象可以替换程序中父类对象出现的任何地方&#xff0c;并且保证原有程序逻辑的正确性不被破坏。 比如我们在实际开发中定义了数据读取的父类&#xff0c;子类可以进行在此功能的拓展、增强但是不能修改原有的内在含义。 里氏替换原则和多态的区别&#xff0c;多态…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

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

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

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...