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

红黑树 学习笔记

目录

1.红黑树的概念

1.1红黑树的规则

1.2红黑树的效率

2.红黑树的实现

2.1红黑树的大致结构

2.2红黑树的插入

2.2.1红黑树插入的大致过程

2.2.2情况1:变色

2.2.3情况2:单旋+变色

2.2.4情况3:双旋+变色

2.3红黑树的查找


1.红黑树的概念

红黑树是一颗搜索二叉树,相比于搜索二叉树,红黑树中的每个节点增加了一个存储位置来表示节点的颜色,可以是红色或黑色。通过对于任何一条从根到叶子的路径上各个节点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍,因此红黑树也算比较平衡的树。

1.1红黑树的规则

1.每个节点不是红色就是黑色。

2.根节点是黑色的

3.如果一个节点是红色的,那么该节点的两个孩子节点必须为黑色,也就是说红黑树中,任何路径都不会包含连续的红色节点。

4.对于任意一个节点,从该节点到其所有的NULL节点的简单路径上,均包含相同数量的黑色节点。

例如

1.2红黑树的效率

假设N是红黑树中的节点数量,h为红黑树中最短路径的长度,对于2^{h} - 1 <= N < 2^{2*h} -1, 由此可推出,红黑树增删查改最坏的情况也就是走 2*\log N ,那么时间复杂度也就为 O(\log N)。

例如

2.红黑树的实现

2.1红黑树的大致结构

enum COLOUR
{RED,BLACK
};//COLOUR 来控制每个节点的颜色template<class K, class V>
struct RBTreeNode
{pair<K, V> _value;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;COLOUR _col;//    RED/BLACKRBTreeNode(const pair<K, V>& value):_value(value), _left(nullptr), _right(nullptr), _parent(nullptr),_col(RED) // 默认为红色,因为黑色会改变路径节点数量相等规则,较为麻烦{}
};template<class K, class V>
class RBTree
{using Node = RBTreeNode<K,V>;
public://... ...
private:Node* _root = nullptr;size_t num = 0;//记录节点数量
};

2.2红黑树的插入

2.2.1红黑树插入的大致过程

  1. 插入一个新节点时,按照二叉搜索树的规则进行插入,插入之后我们只需要判断是否符合红黑树的4条规则。
  2. 如果是空树插入,新增加的节点为黑色节点(也就是根节点)。如果是非空树插入,新增节点必须为红色节点。因为插入黑色节点,对于红黑树的每条路径黑色节点数量均相同的规则,我们很难处理。
  3. 非空树插入后,新增节点必须是红色的,如果父节点为黑色,则不违反规则,插入结束。
  4. 非空树插入后,若父节点为红色节点,则违反规则,因为不能出现连续的红色节点。进一步分析为以下几种情况:

2.2.2情况1:变色

例如上述的一种情况,x节点是我们的新插入节点,很明显,x和6构成了连续的红色节点,并且此时的g为黑u存在且为红。我们如果想要红黑树符合规则,必须将6的颜色变为黑色,但是在18->10->6->x这条路径上,就会多一个黑色节点,又会破坏规则。那么我们这么想:对于一个黑色节点,如果把该节点变为红色,同时把该节点的两个左右节点变为黑色,那么其实不会改变每一条路径上的黑色节点数量。例如:

我们将10变为红色,将6,15变为黑色。这样既满足了x与6不为连续的红色,也满足了每条路径上的黑色节点数量不变。

以上只是变色中的一种情况,同AVL树一样,如果我们将抽象图画出来,其实本质还是一样,不断往上变色,直到符合红黑树的规则即可。该情况的代码如下:

bool _Insert(const pair<K,V>& value)
{if (_root == nullptr){_root = new Node(value);_root->_col = BLACK;num++;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (value < cur->_value){parent = cur;cur = cur->_left;}else if (cur->_value < value){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(value);if (cur->_value < parent->_value){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;    //节点已经被插入,下面考察是否符合红黑树规则while (parent && parent->_col == RED){Node* grandfather = parent->_parent;//找到父节点的父亲if (parent == grandfather->_left)//如果父亲在grandfather的左边{Node* uncle = grandfather->_right;//那么uncle就在grandfather右边if (uncle && uncle->_col == RED)//如果uncle存在并且为红色,一直往上变色即可{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//... ...

2.2.3情况2:单旋+变色

该情况下,肯定c和p为两个连续的红色节点,但此时g为黑,u不存在或者u存在且为黑。如果u存在且为黑,那么c一定不是新插入节点,否则就会所有路径黑色节点数量不同,如果u不存在,则c一定是新插入节点。

分析:和情况1一样,这里的p必须变为黑色,才能解决连续红色节点的问题,u不存在或者存在且为黑,这里单纯的变色就无法解决问题,因此我们需要旋转+变色。

对于上方左右两种情况,因为g为黑,因此我们进行单旋之后,g就会变成p的子树,此时我们把g变红,把p变黑即可解决问题。并且我们不需要继续向上更新,因为p已经变成这棵子树的根,且为黑色节点,一定不会和上方产生矛盾。

先看上方的图,如果c为新插入的节点,且u存在为黑,那么c左右都为空,红黑树规则就会被打破。所以c之前为黑,然后从下方子树一直往上变为红。

如果u不存在,那么c一定是新插入的节点。如果c不是新插入的节点,那么就说明插入之前就存在红黑树符合规则,所以c和p不连续为红,此时就不符合所有路径黑色节点数量相等,因为g的右边为空,所以假设不成立,c一定是新插入的节点。

然后我们再看旋转+变色之后的结果,都符合了红黑树的规则。左单旋与上面类似。

代码如下:

if (parent == grandfather->_left)
{Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED)//情况1{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left)//情况2{RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;break;}else//情况3{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;break;}}
}

2.2.4情况3:双旋+变色

情况3还是,c,p为红,g为黑,u不存在或者存在且为黑。u不存在,c一定是新增节点,u存在且为黑,c一定不是新增节点。

这里和情况2类似,我们只考虑左边的情况(右边逻辑类似):

我们学过AVL树都知道,尽管不变色,对于这种 < 类型的树,我们必须进行双旋,才能解决问题,< 进行 左右双旋,然后根据结果来看,我们只需要将c变为黑色,将p,g变为红色即可。

之后就是当p为g的右边,逻辑只是和上面的相反,这里就之间展示整个插入的代码:

bool _Insert(const pair<K,V>& value)
{if (_root == nullptr){_root = new Node(value);_root->_col = BLACK;num++;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (value < cur->_value){parent = cur;cur = cur->_left;}else if (cur->_value < value){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(value);if (cur->_value < parent->_value){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//插入完毕,准备检查是否为规则红黑树while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left)//如果p在g的左边{Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED)//u存在且为红,一直向上变色{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//u不存在或者存在且为黑{if (cur == parent->_left)//c为p的左,右单旋+变色{RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;break;}else//c为p的右,左右双旋+变色{RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;break;}}}//      g//   u     p//       c//else//p为g的右{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED)//u存在且为红,一直向上变色{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//u不存在或者存在且为黑{if (cur == parent->_right)//c为p的右,左单旋+变色{RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;break;}else//c为p的左,右左双旋+变色{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;break;}}}}_root->_col = BLACK;//无论如何,根节点都为黑色num++;//统计红黑树的节点数量return true;
}

2.3红黑树的查找

红黑树的查找和AVL树类似,查找效率为O(\log N),代码如下:

Node* find(const K& key)
{Node* cur = _root;while (cur){if (key < cur->_value.first){cur = cur->_left;}else if (key > cur->_value.first){cur = cur->_right;}else{return cur;}}return nullptr;
}

以上内容若有错误,欢迎批评指正!

相关文章:

红黑树 学习笔记

目录 1.红黑树的概念 1.1红黑树的规则 1.2红黑树的效率 2.红黑树的实现 2.1红黑树的大致结构 2.2红黑树的插入 2.2.1红黑树插入的大致过程 2.2.2情况1&#xff1a;变色 2.2.3情况2&#xff1a;单旋&#xff0b;变色 2.2.4情况3&#xff1a;双旋变色 2.3红黑树的查找…...

linux更改系统时间

测试环境和生产环境代码完全一致&#xff0c;但是生产环境代码碰到了问题&#xff0c;报错类似time expired&#xff0c;猜测和系统时间有关系&#xff0c;修改之后确实好了。测试如下&#xff1a; 参考&#xff1a;centos7时间同步教程_centos7 时间同步&#xff0c;如果遇到…...

B站C#刘铁猛笔记

C#——刘铁猛笔记 类、名称空间&#xff08;简述&#xff09; 类&#xff08;class&#xff09;是构成程序的主体 名称空间&#xff08;namespace&#xff09;以树形结构组织类&#xff08;其他类型&#xff09; 名称空间&#xff1a;名称空间是用来组织和管理类、接口、结构…...

如何使用信号发生器产生正弦波并用数字示波器进行测量

使用信号发生器产生正弦波并用数字示波器进行测量的步骤如下&#xff1a; 1. 准备工作 所需设备 信号发生器数字示波器探头&#xff08;通常为10X衰减探头&#xff09;BNC电缆和适配器&#xff08;如果需要&#xff09; 2. 设置信号发生器 连接 使用BNC电缆将信号发生器的…...

XJ04、消费金融|授信基本概念及其流程设计

银行是经营风险的特殊行业&#xff0c;而银行授信则与银行业务和风险天然相伴。它是银行与客户建立业务关系的起点&#xff0c;也是银行风险管理的关键环节和核心要素。若要了解银行业务&#xff0c;就得先了解银行的授信业务&#xff1b;若要理解银行经营&#xff0c;就得先理…...

儿童预防接种预约微信小程序springboot+论文源码调试讲解

2相关技术 2.1微信小程序 小程序是一种新的开放能力&#xff0c;开发者可以快速地开发一个小程序。小程序可以在微信内被便捷地获取和传播&#xff0c;同时具有出色的使用体验。尤其拥抱微信生态圈&#xff0c;让微信小程序更加的如虎添翼&#xff0c;发展迅猛。 2.2 MYSQL数据…...

nginx 修改配置

如果你的后端服务在不同的端口上运行&#xff0c;但静态资源访问路径相同&#xff0c;你可以使用 Nginx 的 location 配置来将请求转发到不同的后端服务&#xff0c;同时处理静态文件。这里有几种常见的方式&#xff1a; 方案 1: 基于路径的配置 如果所有服务的静态资源路径相…...

孤岛架构在安全性方面

孤岛架构在安全性方面的考虑主要涉及如何确保每个孤岛的安全性&#xff0c;同时维护整个系统的安全。 关键的安全性考虑&#xff1a; 1. 数据隔离和访问控制 数据隔离&#xff1a;每个孤岛应该有独立的数据存储&#xff0c;以确保数据隔离。这有助于防止数据泄露和未经授权的…...

COSCon'24 志愿者招募令:共创开源新生活!

亲爱的开源爱好者们&#xff0c; 第九届中国开源年会&#xff08;COSCon24&#xff09;即将在北京中关村国家自主创新示范区会议中心于2024年11月2日至3日隆重举行。今年的主题是“Open Source, Open Life&#xff5c;开源新生活”&#xff0c;旨在探索开源技术如何在各个领域推…...

vscode使用make编译c的问题

问题1&#xff1a;makefile:2: *** missing separator. Stop vscode的配置问题&#xff0c;看这哥们的文章即可&#xff1a;https://blog.csdn.net/m0_57464986/article/details/134220676 问题2&#xff1a;创建makefile文件 直接创建文件名为“makefile”的文件即可&#x…...

管家婆财贸ERP BB019.操作员制单日期控制

最低适用版本&#xff1a; 财贸系列 20.0 插件简要功能说明&#xff1a; 定制操作员权限功能&#xff0c;根据服务器日期控制系统单据新增和修改更多细节描述见下方详细文档 插件操作视频&#xff1a; 进销存类定制插件--操作员制单日期控制 插件详细功能文档&#xff1a; …...

从 Vue 2 到 Vue 3:全面升级指南

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:Vue-从 Vue 2 到 Vue 3&#xff1a;全面升级指南 前言 随着前端技术的不断发展&#xff0c;Vue.j…...

Apache paimon表操作实战-5

维表Join Paimon支持Lookup Join语法,它用于从 Paimon 查询的数据来补充维度字段。要求一个表具有处理时间属性,而另一个表由查找源连接器支持。 Paimon 支持 Flink 中具有主键的表和append-only的表查找联接。以下示例说明了此功能。 USE CATALOG fs_catalog; CREATE TABL…...

阿里云用STS上传oss的完整程序执行流程图 和前端需要哪些参数uniapp

H5 微信小程序可用的前端直传阿里云OSS(STS临时凭证前端签名)直接下载插件 下面是原理说明&#xff1a; 明白了&#xff0c;我来详细说明前端上传文件到阿里云OSS需要携带的具体参数&#xff1a; 从服务器获取的 STS 凭证&#xff1a; // 这些参数需要从你的后端服务器获…...

决策树方法根据指定条件筛选方案

代码功能说明 条件类&#xff1a;Condition 类用于定义每个条件的范围&#xff0c;并提供一个方法 is_satisfied 来检查输入值是否满足该条件。 算法选择器类&#xff1a;AlgorithmSelector 类负责应用条件并记录不满足的条件。它提供方法 apply_condition 用于更新可用算法&a…...

多特征变量序列预测(四) Transformer-BiLSTM风速预测模型

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享&#xff01; EMD、EEMD、FEEMD、CEEMD、CEEMDAN的区别、原理和Python实现&#xff08;一&#xff09;EMD-CSDN博客 EMD、EEM…...

【开源免费】基于SpringBoot+Vue.JS蜗牛兼职平台 (JAVA毕业设计)

本文项目编号 T 034 &#xff0c;文末自助获取源码 \color{red}{T034&#xff0c;文末自助获取源码} T034&#xff0c;文末自助获取源码 目录 一、系统介绍1.1 平台架构1.2 管理后台1.3 用户网页端1.4 技术特点 二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景…...

Ajax笔记

介绍 Ajax是一种网页开发技术&#xff0c;全称是Asynchronous JavaScript and XML&#xff08;异步JavaScript和XML&#xff09;。作用如下&#xff1a; 数据交换&#xff1a;可以通过Ajax给服务器发送请求&#xff0c;并获取服务器响应的数据。即前端动态的发送Ajax到服务器端…...

软考:缓存分片和一致性哈希

缓存分片技术是一种将数据分散存储在多个节点上的方法&#xff0c;它在分布式缓存系统中尤为重要。这项技术的核心目的是提高系统的性能和可扩展性&#xff0c;同时确保数据的高可用性。以下是缓存分片技术的一些关键点&#xff1a; 数据分片&#xff1a;缓存分片涉及将数据分成…...

3109 体验积分值

经验值&#xff1a;1200 时间限制&#xff1a;1000毫秒 内存限制&#xff1a;128MB 合肥市第34届信息学竞赛&#xff08;2017年&#xff09; 不许抄袭&#xff0c;一旦发现&#xff0c;直接清空经验&#xff01; 题目描述 Description 卡卡西和小朋友们做完了烧脑的数字游…...

初识jsp

学习本章节前建议先安装Tomcat web服务器&#xff1a;tomcat下载安装及配置教程_tomcat安装-CSDN博客 1、概念 我的第一个JSP程序&#xff1a; 在WEB-INF目录之外创建一个index.jsp文件&#xff0c;然后这个文件中没有任何内容。将上面的项目部署之后&#xff0c;启动服务器…...

Ansible 的脚本 --- playbooks剧本

playbooks 本身由以下各部分组成 &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Vars&#xff1a;变量 &#xff08;3&#xff09;Templates&#xff1a;模板 &a…...

Windows 死机时 系统错误日志分析与故障排除

目录 前言正文 前言 对于服务器异常重启&#xff0c;推荐阅读&#xff1a;详细分析服务器自动重启原因&#xff08;涉及Linux、Window&#xff09; 以下主要做一个总结梳理 正文 查看系统事件日志&#xff1a; 可以查看系统事件日志&#xff0c;找出可能导致系统崩溃的错误…...

基于pytorch搭建CNN

先上代码 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torchvision import datasets, transforms import matplotlib.pyplot as plt import numpy as np import pandas as pd import matplotlibmatplotlib.use(tkA…...

C#实现与Windows服务的交互与控制

在C#中&#xff0c;与Windows服务进行交互和控制通常涉及以下几个步骤&#xff1a; 创建Windows服务&#xff1a;首先&#xff0c;需要创建一个Windows服务项目。可以使用Visual Studio中的“Windows 服务 (.NET Framework)”项目模板来创建Windows服务。 配置服务控制事件&am…...

Java和Ts构造函数的区别

java中子类在使用有参构造创建对象的时候不必要必须调用父类有参构造 而js则必须用super()调用父类的有参构造,即使用不到也必须传递 Java 中的处理方式 可选择性参数: 在 Java 中&#xff0c;当子类使用父类的有参构造方法创建对象时&#xff0c;可以只传递需要的参数。如果父…...

植物健康,Spring Boot来助力

3系统分析 3.1可行性分析 通过对本植物健康系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本植物健康系统采用SSM框架&#xff0c;JAVA作为开发语言&#…...

百度文心一言接入流程-java版

百度文心一言接入流程-java版 一、准备工作二、API接口调用-java三、百度Prompt工程参考资料: 百度文心一言:https://yiyan.baidu.com/百度千帆大模型:https://qianfan.cloud.baidu.com/百度千帆大模型文档:https://cloud.baidu.com/doc/WENXINWORKSHOP/index.html千tokens…...

Java 11 新特性深度解析与应用实践

Java 作为一种广泛应用的编程语言&#xff0c;不断演进以满足开发者日益增长的需求和适应技术的发展趋势。Java 11 带来了一系列重要的新特性和改进&#xff0c;这些变化不仅提升了语言的性能和功能&#xff0c;还为开发者提供了更好的开发体验和工具。本文将深入探讨 Java 11 …...

druid 连接池监控报错 Sorry, you are not permitted to view this page.本地可以,发布正式出错

简介&#xff1a; druid 连接池监控报错 Sorry, you are not permitted to view this page. 使用Druid连接池的时候&#xff0c;遇到一个奇怪的问题&#xff0c;在本地&#xff08;localhost&#xff09;可以直接打开Druid连接池监控&#xff0c;在其他机器上打开会报错&#…...

做视频网站 服务器/肇庆网络推广

先引入jQuery和jqprint插件&#xff0c;为了处理jQuery和jqprint插件的版本不兼容问题&#xff0c;在引入jquery-migrate 文件 https://download.csdn.net/download/y1534414425/13609110 代码如下 <!DOCTYPE html> <html lang"en"><head><me…...

没有网站可以做京东联盟吗/如何在百度搜索到自己的网站

第一章 行星地球第一节 宇宙中的地球>>>>一、地球在宇宙中的位置1. 天体是宇宙间物质存在的形式&#xff0c;如恒星、行星、卫星、星云、流星、彗星。2. 天体系统&#xff1a;天体之间相互吸引和相互绕转形成天体系统。3. 天体系统的层次由大到小是&#xff1a;>…...

东莞市seo网络推广平台/关键词seo公司真实推荐

本主题将从3个角度进行对比常见设置&#xff08;CentOS 6 vs CentOS 7&#xff09;服务管理&#xff08;Sysvinit vs Upstart vs Systemd&#xff09;性能测试&#xff08;cpu/mem/io/oltp&#xff09;本文为第三部分&#xff1a;性能测试的对比1. CPU测试工具: 通过sysbench对…...

bbs网站怎么做/易思企业网站管理系统

1、总是在幻想&#xff0c;却很少实际行动&#xff0c;结果发现教材看得少的可怜。 2、每天起很早&#xff0c;睡很晚&#xff0c;觉得自己很努力&#xff0c;其实都是在愣神&#xff0c;效率极低。 3、一有压力就想吃东西&#xff0c;一吃东西就撑&#xff0c;一撑就脑供血不足…...

怎么自己做个网站/互联网推广是做什么的

1.desc 表名;–查看表的数据结构 2.select database();–查看当前所在数据库 3.distinct&#xff1b;–去重 4.MySQL中的"“号含义: 1.只做运算符 2.如果有字符串则尝试转换成数字&#xff0c;如果能转成数字则返回数字&#xff0c;如果不能则返回0 3.使用”"号拼接时…...

长春疫情最新消息今天新增病例/aso优化什么意思是

系列63 物理学原理光学 应用非透明标签探测 标签宽度2 mm 标签间隙2 mm 介质不透明 供电电压 UB10 ... 30 V, DC 输入端 示教输入数1 光束 输出 数字开关量输出数1 光束 开关量输出1 开关元件晶体管, 推挽 开关原理标签上的开关信号 槽宽3 mm 槽深61 mm 尺寸&#xff08;宽 x…...