C++:平衡二叉搜索树之红黑树

一、红黑树的概念

红黑树, 和AVL都是二叉搜索树, 红黑树通过在每个节点上增加一个储存位表示节点的颜色, 可以是RED或者BLACK, 通过任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树能够确保没有一条路径会比其他路径长出两倍,因此红黑树是接近平衡的

与AVL树相比,红黑树的插入和删除操作更具优势,因为红黑树是接近平衡的,AVL树是绝对平衡的, 因此插入删除等操作时,红黑树需要旋转的次数是比AVL树少的。

二、红黑树的性质

  1. 每个节点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子节点是黑色的
  4. 一条路径上没有连续的红色节点, 每条路径上黑色节点的数量是相同的

下面就是一个红黑树的示例:

根据红黑树的性质我们知道:一个红黑树中,最短路径 * 2 >= 最长路径

理论上:最短路径:全黑 最长路径:一黑一红交替

三、红黑树节点的定义

下面是红黑树节点的定义代码:

//节点的颜色定义
enum Colour
{RED,BLACK
};
//节点结构体
template<class K, class V>
struct RBTreeNode
{pair<K, V> _kv;//节点的数据RBTreeNode<K, V>* _left;//节点的左孩子RBTreeNode<K, V>* _right;//节点的右孩子RBTreeNode<K, V>* _parent;//节点的双亲节点Colour _col;//节点的颜色//节点的构造函数RBTreeNode(const pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};

四、红黑树的插入

红黑树是在二叉搜索树的基础上加上使其近似平衡的限制条件, 因此红黑树的插入可以分成以下两步:

1、按照二叉搜索树的性质插入新节点

2、检测新节点插入后,红黑树的性质是否遭到破坏

新节点的默认颜色是红色,因此,如果双亲节点是黑色就没有违反任何红黑树的性质,不需要调整,但是如果新插入节点的双亲节点是红色时, 就违反了不能有相连的红色节点的规则,此时需要对红黑树进行分情况讨论:

cur为当前节点, p为父节点, g为祖父节点, u为叔父节点

4.1情况一:cur 为红, p为红, g为黑, u存在且为黑

注意:这里的树,可能是一棵完整的树, 也可能是一个子树

此时abcde子树都为空

这个时候我们只需要进行变色处理, 将p 和 u节点变为黑色, 将g改为红色

调整完以后,如果g是根节点, 需要将g改为黑色, 因为红黑树的性质规定根节点的颜色必须是黑色。

如果g是子树,并且g的双亲节点是红色的话就需要继续向上调整, 如下图所示:

4.2情况二: cur为红, p为红, g为黑, u不存在/u存在且为黑

这里说明u的情况有两种:

1.u不存在, 此时cur一定是新增节点, 如果cur不是新增节点的话, 那么cur和p一定有一个节点的颜色是黑色, 但是那样就不满足每条路径黑色节点的数目相同这一性质。

p是g的左子节点, cur是p的左子节点, 那么就对g进行右单旋:

变色处理:p, g变色 – p变黑色, g变红色

p是g的右子节点, cur是p的右子节点, 那么就对g进行左单旋:

变色处理:p, g变色 – p变黑色, g变红色

p是g的左子节点, cur是p的右子节点,先对p进行左单旋, 再对g做右单旋:

变色处理:cur, g变色 – cur变黑色, g变红色

先进行左单旋;

再进行右单旋:

p是g的右子节点, cur是p的左子节点, 先对p进行右单旋, 再对g进行左单旋:

变色处理:cur, g变色 – cur变黑色, g变红色

先进行右单旋:

再进行左单旋:

2.u存在且为黑, 那么cur节点原来的颜色一定是黑色, 现在是红色的原因就是因为cur的子树在调整的过程中将cur的颜色更新成了红色。

p是g的左子节点, cur是p的左子节点, 那么就对g进行右单旋:

变色处理:p, g变色 – p变黑色, g变红色

p是g的右子节点, cur是p的右子节点, 那么就对g进行左单旋:

变色处理:p, g变色 – p变黑色, g变红色

p是g的左子节点, cur是p的右子节点,先对p进行左单旋, 再对g做右单旋:

变色处理:cur, g变色 – cur变黑色, g变红色

先进行左单旋:

再进行右单旋:

p是g的右子节点, cur是p的左子节点, 先对p进行右单旋, 再对g进行左单旋:

变色处理:cur, g变色 – cur变黑色, g变红色

先进行右单旋:

再进行左单旋:

左单旋代码实现:

//左单旋void RotateL(Node* parent){Node* SubR = parent->_right;Node* SubRL = SubR->_left;parent->_right = SubRL;if (SubRL){SubRL->_parent = parent;}Node* parentP = parent->_parent;SubR->_left = parent;parent->_parent = SubR;if (parentP == nullptr){_root = SubR;SubR->_parent = nullptr;}else{if (parentP->_left == parent){parentP->_left = SubR;SubR->_parent = parentP;}else{parentP->_right = SubR;SubR->_parent = parentP;}}}

右单旋代码实现:

//右单旋void RotateR(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;parent->_left = SubLR;if (SubLR)SubLR->_parent = parent;Node* parentP = parent->_parent;SubL->_right = parent;parent->_parent = SubL;if (parentP == nullptr){_root = SubL;SubL->_parent = nullptr;}else{if (parentP->_left == parent){parentP->_left = SubL;SubL->_parent = parentP;}else{parentP->_right = SubL;SubL->_parent = parentP;}}}

插入函数整体代码实现:

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->_col = RED;if (parent->_kv.first > kv.first){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//处理while (parent && parent->_col == RED){Node* grandfather = parent->_parent;// g//p  u结构if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){//变色处理parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//uncle不存在或者存在且为黑-》旋转加变色{if (cur == parent->_left){//cur为parent的左子结点时进行右旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{//双旋RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){//cur为父亲的右子节点时对g进行左单旋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;}

五、红黑树相关接口的实现

查找函数的实现:

依旧是根据二叉搜索树的查找规则:

//查找函数Node* Find(const K& key){if (_root == nullptr)return nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}elsereturn cur;}return nullptr;}

容量高度相关:

返回有效节点个数:

//有效节点个数int Size(){_Size(_root);}int _Size(Node* root){return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;}

二叉树高度:

//平衡二叉树高度int Height(){_Height(_root);}int _Height(Node* root){if (root == nullptr)return 0;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}

中序遍历:

//中序遍历void Inorder(){_inorder(_root);cout << endl;}void _inorder(Node* root){if (root == nullptr){return;}_inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_inorder(root->_right);}

六、红黑树的验证

我们要通过代码来验证我们所实现的红黑树是否是符合红黑树的性质的。

红黑树的验证分为以下两步:

  1. 验证其是否满足二叉搜索树也就是中序遍历是否有序
  2. 验证其是否满足红黑树的性质

验证代码:

1、验证是否为二叉搜索树:

//中序遍历void Inorder(){_inorder(_root);cout << endl;}void _inorder(Node* root){if (root == nullptr){return;}_inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_inorder(root->_right);}

2、验证是否满足红黑树的性质:

//判断是否为红黑树bool IsBalance(){if (_root == nullptr)return true;if (_root->_col == RED){return false;}// 参考值int refNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){++refNum;}cur = cur->_left;}return Check(_root, 0, refNum);}bool Check(Node* root, int blackNum, const int refNum){if (root == nullptr){//cout << blackNum << endl;if (refNum != blackNum){cout << "存在黑色节点的数量不相等的路径" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << root->_kv.first << "存在连续的红色节点" << endl;return false;}if (root->_col == BLACK){blackNum++;}return Check(root->_left, blackNum, refNum)&& Check(root->_right, blackNum, refNum);} 

通过以上几段代码就能完成对我们实现的红黑树验证。

七、红黑树与AVL数的比较

红黑树和AVL树都是平衡二叉搜索树, 进行增删查改的操作时的时间复杂度都是O(logN), 红黑树不追求绝对平衡, AVL树追求绝对平衡,相对而言红黑树在维持平衡时的旋转次数要少于AVL树, 因此在经常进行插入和删除的结构中红黑树的性能一般要优于AVL树, 因此是实际中使用红黑树更多。

八、红黑树的应用

  1. C++ STL库中的map/set 、mutil_map/mutil_set的实现
  2. java库
  3. linux内核

不止以上三处使用, 这里仅是为了举例。


关于红黑树的介绍到这里就结束了, 希望大家通过这篇文章能都红黑树有一定的理解, 以下是红黑树的具体代码实现链接:

红黑树具体实现代码

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Selenium + Python 自动化测试12(unittest组织更多用例)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了unittest中test suite 的构建&#xff0c;可以测试多条测试用例。 本篇文章我们接着讲。使用discover()方法构建更多的测试用例。 1、引入需要完成的任务 上…

【网络编程】基于UDP的TFTP文件传输

1&#xff09;tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再…

Linux进程间通信学习记录(IPC 机制、共享内存以及信号灯集)

0.System V IPC机制&#xff1a; ①.IPC对象包含&#xff1a;共享内存、消息队列和信号灯集。 ②.每个IPC对象有唯一的ID。 ③.IPC对象创建后一直存在&#xff0c;直到被显示地删除。 ④.每一个IPC对象有一个关联的KEY。&#xff08;其他进程通过KEY访问对应的IPC对象&#xff…

Ubuntu安装Anaconda3

本文详细阐述了在 Ubuntu 系统中安装 Anaconda3 的完整流程。包括 Anaconda3 安装包的获取途径&#xff0c;具体安装过程中的每一个步骤及注意事项&#xff0c;还有安装后的环境变量设置和安装成功的验证方法。旨在为 Ubuntu 用户提供清晰、易懂且准确的 Anaconda3 安装指南&am…

Unity--AssetBundle AB包管理器

1.简介 AB包&#xff08;AssetBundle&#xff09;是Unity中用于资源管理的一种机制&#xff0c;它允许开发者将多个文件&#xff08;如纹理、模型、音频等&#xff09;打包成一个单独的文件&#xff0c;以便于在游戏运行时动态加载和卸载。 但是现在出现了最新的Addressable来…

docker部署drawio

1&#xff09;介绍Drawio.io GitHub&#xff1a;GitHub - jgraph/drawio: draw.io is a JavaScript, client-side editor for general diagramming. Draw.io是一款开源的绘制流程图的工具&#xff0c;拥有大量免费素材和模板。程序本身支持中文在内的多国语言&#xff0c;创建…

【学习笔记】多元线性回归模型 —— Matlab

文章目录 前言一、多元线性回归多元线性回归模型线性模型 ( Y , X β , σ 2 I n ) (Y,X\beta,\sigma^2I_n) (Y,Xβ,σ2In​) 考虑的主要问题多元线性回归模型的参数估计多元线性回归模型和回归系数的检验 二、示例三、代码实现----Matlab1.多元回归的实现2.逐步回归的实现3.M…

图像增强技术简介

目录 一、概论 二、图像噪声 三、图像增强处理分类 一、概论 图像增强作为基本的图像处理技术&#xff0c;其目的是对图像进行加工&#xff0c;以得到对具体应用来说视觉效果更“好”更“有用”的图像。图像增强算法并不能增加原始图像的信息&#xff0c;而是通过某种技术手…

MVCC 详解

MVCC 简单理解 MVCC&#xff0c;全称 Multi-Version Concurrency Control&#xff0c;是多版本并发控制的意思。 在高并发情况下操作数据库可能会出现脏写、脏读、不可重复度、幻读这四个问题。通过 MVCC 可以实现在不加锁的前提下避免一些问题。 MVCC 的实现原理 多版本 …

相似度计算方法-编辑距离 (Edit Distance)

定义 编辑距离&#xff08;Edit Distance&#xff09;&#xff0c;也称为Levenshtein距离&#xff0c;是一种衡量两个字符串相似度的方法。它定义为从一个字符串转换为另一个字符串所需的最少单字符编辑操作次数&#xff0c;这些操作包括插入、删除或替换一个字符。 计算方法 …

Openstack二层网络的构建和使用

Openstack二层网络的构建和使用 一、实验目的 &#xff08;1&#xff09;了解网络层级、子网、动态地址、网关代理等概念并进行应用。 &#xff08;2&#xff09;了解OpenStack项目以及相关组件。 &#xff08;3&#xff09;了解 Neutron 二层网络的构建和使用。 二、实验原…

tomcat Listener 内存马浅谈

本文来源无问社区&#xff0c;更多实战内容可前往查看http://www.wwlib.cn/index.php/artread/artid/3651.html Tomcat 介绍 Tomcat的主要功能 toncat作为一个web服务器&#xff0c;实现了两个核心的功能 http 服务器功能&#xff1a;进行socket 通信&#xff08;基于TCP/I…

案例分享—国外深色UI界面设计赏析

在国外&#xff0c;深色界面设计&#xff08;Dark Mode&#xff09;已成为提升用户体验的重要趋势。它不仅有效减少屏幕亮度&#xff0c;保护用户视力&#xff0c;还能在夜晚或低光环境下提供更加舒适的浏览体验。设计师们普遍认识到&#xff0c;深色主题不仅提升了应用的视觉层…

Vue中下载内容为word文档

1.使用 html-docx-js&#xff1a;这是一个将 HTML 转换为 Word 文档的库。 2. 利用 Blob 和 FileSaver.js&#xff1a;创建并下载生成的 Word 文档。 在 Vue.js 中实现步骤如下: 1. npm 安装 html-docx-js 和 file-saver npm install html-docx-js npm install file-saver2.…

【vue教程】六. Vue 的状态管理

目录 往期列表本章涵盖知识点回顾Vuex 的基本概念什么是 Vuex&#xff1f;为什么需要 Vuex&#xff1f; Vuex 的核心概念stategettersmutationsactionsmodules Vuex 的安装和基本使用安装 Vuex创建 store在 Vue 应用中使用 store在组件中访问和修改状态 Vuex 的模块化模块化的好…

2024新型数字政府综合解决方案(七)

新型数字政府综合解决方案通过集成人工智能、大数据、区块链和云计算技术&#xff0c;创建了一个高度智能化和互联互通的政府服务平台&#xff0c;旨在全面提升行政效率、服务质量和透明度。该平台实现了跨部门的数据整合与实时共享&#xff0c;利用人工智能进行智能决策支持和…

PCRNet: Point Cloud Registration Network using PointNet Encoding 论文解读

目录 一、导言 二、先导知识 1、Frobenius范数 三、相关工作 1、点云配准工作 2、PointNet 3、基于深度学习的点云配准 四、PCRNet 1、PCRNet 2、Iterative PCRNet 3、损失函数 五、实验 一、导言 本论文收录于CVPR2019&#xff0c;本论文提出了一种依赖PointNet网…

11.2.0.4 RAC 节点1重做操作系统后如何复原

环境描述&#xff1a;Redhat7.9 11.2.0.4 RAC 双节点 实验背景 群里有大佬在交流RAC中1个节点操作系统坏了如何修复&#xff0c;故有了该实验。 在正常的生产环境当中&#xff0c;有时候会遇到主机磁盘以及其他硬件故障导致主机OS系统无法启动&#xff0c;或者OS系统本身故障…

【海奇HC-RTOS平台E100-问题点】

海奇HC-RTOS平台E100-问题点 ■ btn 没有添加到group中 &#xff0c;怎么实现的事件的■ 屏幕是1280*720, UI是1024*600,是否修改UI■ hc15xx-db-e100-v10-hcdemo.dtb 找不到■ 触摸屏驱动 能否给个实例■ 按键驱动■ __initcall(projector_auto_start)■ source insigt4.0 #if…

【esp32程序编译提示undefined reference to ‘xxxx‘】

案例1&#xff1a; 【背景】 在使用SquareLine Studio设计UI时&#xff0c;成功导出UI代码&#xff0c;在编译代码的时候提示undefined reference to ‘ui_img_1869164015’&#xff0c;有一个变量无法识别&#xff0c;没有定义。 【定位步骤】 1.首先找到用这个变量的.c文件…