C++----红黑树 - 详解

news/2025/9/29 12:55:24/文章来源:https://www.cnblogs.com/lxjshuju/p/19118561

概念

红黑树是一种自平衡二叉搜索树,通过节点颜色标记和旋转/重染色操作保持近似平衡,从而保证查找、插入和删除操作的时间复杂度为 O(log n)

红黑树必须满足以下 五大性质

  1. 每个节点要么是红色,要么是黑色。

  2. 根节点是黑色。

  3. 所有叶子节点(NIL 空节点)都是黑色。

  4. 如果一个节点是红色,那么它的两个子节点必须是黑色(不允许出现两个连续的红节点)。

  5. 从任意节点到其所有叶子节点的路径上,包含的黑色节点数必须相同(即“黑高”相等)。

为什么满足上面的性质,红黑树就能保证:其最长路径不会超过最短路径的两倍?

  1. 最短路径

    • 一条路径上全是黑色节点(不可能有红色节点夹杂)。

    • 因为黑高在所有路径上一致,所以这是最短的可能路径。

  2. 最长路径

    • 在黑色节点之间插入红色节点,使路径尽可能“长”。

    • 由于性质 (4),红色节点不能连续,最多只能在每个黑色节点后面跟一个红色节点。

    • 所以 最长路径的节点数 ≤ 2 × 黑色节点数

  3. 比例关系

    • 最短路径长度 = 黑高 (bh)。

    • 最长路径长度 ≤ 2 × bh。

因此,最长路径不会超过最短路径的两倍

代码实现

红黑树节点

与avl树不同,红黑树的节点不需要平衡因子来控制树的高度,而需要一个变量存储是红还是黑。其他的都是相同的,我们使用了结构体来定义红黑,除此以外,在对节点进行初始化,要对节点初始化为红,为什么呢?因为一般都是在插入时才会初始化节点。那我们想一想,插入红的方便处理还是黑的方便处理?如果是黑的就违背了性质5,处理难度比较大,甚至还会影响其他的性质。如果是红色的话,我们只考虑性质4即可,对其处理也是比较方便,使用改色和旋转即可:

enum Color
{RED,BALCK
};
template
struct RBNode
{RBNode(const pair& kv = kv(),Color color = RED):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_color(color){}RBNode* _left;RBNode* _right;RBNode* _parent;pair _kv;Color _color;
};

定义红黑树:

template
class RBTree
{using node = RBNode;
public:RBTree(node* root=nullptr):_root(root){}bool find(K value){node* cur = _root;while (cur){if (cur->_kv.first < value)cur = cur->_right;else if (cur->_kv.first < value)cur = cur->_left;elsereturn true;}return false;}bool insert(const pair& kv){}
private:node* _root;
};

insert分析

接下来分析insert,插入的逻辑与搜索二叉树是一样的,但是插入完以后,与avl树一样,我们要对其进行检查,检查它是否符合avl树的性质,如果不满足要对其进行变色旋转处理。

	bool insert(const pair& kv){node* newnode = new node(kv);if(!_root){newnode->_color = BALCK;_root = newnode;return true;}node* parent = nullptr;node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}elsereturn false;}if (parent->_kv.first < kv.first){parent->_right = newnode;newnode->_parent = parent;}else{parent->_left = newnode;newnode->_parent = parent;}//检测是否符合二叉树 看看是不是红红相连........}

我们分析,如果插入cur后,发现parent的颜色是红的,就需要进行处理,反之就不需要管。当parent的颜色是红色的时候,有这么两大种情况:

1.uncle存在且为红

上述,cur无论是插在parent的左右,还是在uncle的左右,处理方式都是一样的。

2.uncle不存在,或者存在为黑

uncle不存在或者为黑其实是一样的,不必纠结,因为uncle不存在,但pparent还有一个空节点,空节点在红黑树中都是黑树。所以uncle不存在是一种特例,就是最简单的情况,插入的就是cur,在这种情况下,pparent肯定也只有一个parent,如果存在uncle为黑,那么就不是红黑树了,在插入之前就有错误,所以,最简单的情况就是uncle不存在时。因此我们不再具体展示这种特殊情况的处理方法,直接展示通用的。

存在两种情况,第一种是cur在parent的方向与parent在pparent的方向一致,第二种就是不一致。

a.一致(LL,RR)

这是cur在LL的情况,当cur在RR时也是类似的。那么,当改色完成后,parent还用继续向上循环吗?是不用的,在cur不变红色之前,上面的树都是正常的,所以即使是旋转后,也维持了搜索树的性质,同时仔细观察的话,除了节点的数值发生了变化(pparent变成了parent等),其他的红黑树性质并没有发生改变。所以不需要再向上处理。

b.不一致(LR,RL)

当uncle为空时道理和a是一样的,这里画个图:

看一看扩展情况,其实都是类似的:

此时cur在LR的位置,而cur在RL的处理方式是一样的,不再赘述。当改色完成后不需要再向上处理。

insert代码

	bool insert(const pair& kv){node* newnode = new node(kv);if(!_root){newnode->_color = BALCK;_root = newnode;return true;}node* parent = nullptr;node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}elsereturn false;}if (parent->_kv.first < kv.first){parent->_right = newnode;newnode->_parent = parent;}else{parent->_left = newnode;newnode->_parent = parent;}cur = newnode;//检测是否符合二叉树 看看是不是红红相连while (parent && parent->_color==RED){node* pparent = parent->_parent;if (parent == pparent->_left){node* uncle = pparent->_right;if (uncle && uncle->_color == RED)//情况1 叔叔存在且为红{parent->_color = uncle->_color = BALCK;pparent->_color = RED;cur = pparent;parent = pparent->_parent;}else //叔叔不存在 或存在且为黑{if (cur == parent->_left)//左左{Rotate_R(pparent);parent->_color = BALCK;pparent->_color = RED;}else//左右{Rotate_L(parent);Rotate_R(pparent);cur->_color = BALCK;pparent->_color = RED;}break;}}else//parent在pparent的右边{node* uncle = pparent->_left;if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BALCK;pparent->_color = RED;cur = pparent;parent = cur->_parent;}else{if (cur == parent->_right)//RR{Rotate_L(pparent);parent->_color = BALCK;pparent->_color = RED;}else//RL{Rotate_R(parent);Rotate_L(pparent);cur->_color = BALCK;pparent->_color = RED;}break;}}}_root->_color = BALCK;return true;}void Rotate_R(node* parent){node* L = parent->_left;node* LR = L->_right;parent->_left = LR;if (LR)LR->_parent = parent;L->_right = parent;node* pparent = parent->_parent;parent->_parent = L;if (parent == _root){L->_parent = nullptr;_root = L;}else{L->_parent = pparent;if (pparent->_left == parent)pparent->_left = L;elsepparent->_right = L;}}//左单旋void Rotate_L(node* parent){node* R = parent->_right;node* RL = R->_left;parent->_right = RL;if (RL)RL->_parent = parent;R->_left = parent;node* pparent = parent->_parent;parent->_parent = R;if (parent == _root){R->_parent = nullptr;_root = R;}else{R->_parent = pparent;if (pparent->_left == parent)pparent->_left = R;elsepparent->_right = R;}}

检验是否为红黑树

要检验是否为红黑树,要满足两点:1.中序遍历有序,是二叉搜索树;2.满足红黑树的性质。这里就不再写中序遍历,请读者自行验证。只考虑满足红黑树性质。

考虑:1.根节点为黑;2.红红不能相连;3.各个路径黑点数相等。

第一点容易证明。第二点可以写一个层序遍历判断:

enum Color { RED, BLACK };
struct Node {int key;Color color;Node* left;Node* right;Node(int k, Color c) : key(k), color(c), left(nullptr), right(nullptr) {}
};
bool checkNoRedRed(Node* root) {if (!root) return true;stack st;st.push(root);while (!st.empty()) {Node* curr = st.top();st.pop();// 检查红红相连if (curr->color == RED) {if ((curr->left  && curr->left->color == RED) ||(curr->right && curr->right->color == RED)) {return false; // 发现红红相连}}// 前序:先处理当前,再压右,最后压左if (curr->right) st.push(curr->right);if (curr->left)  st.push(curr->left);}return true;
}

一般用递归来检查数量是否相等,方法是先任意找一条路径计算黑节点数量,再与其他的路径进行对比,看看数量是否一致,如果都一致说明满足,如果不一致说明不满足。为了方便,在检查黑节点数量的递归中顺便检查一下红红是否相连即可:

	bool IsRBtree(){if (!_root)return true;if (_root->_color == RED){cout << "违反了根节点为黑的规则" << endl;return false;}int blacksize = 0;node* cur = _root;while (cur){if (cur->_color == BALCK)blacksize++;cur = cur->_left;}return _IsRBtree(_root, blacksize, 0);}bool _IsRBtree(node* root, int blacksize, int k){int a = 0;if (root == nullptr){if (blacksize != k){cout << "违反了 每条路径黑节点数量相等的规则" << endl;return false;}return true;}if (root->_color == BALCK)k++;node* parent = root->_parent;if (parent && parent->_color == RED && root->_color == RED){cout << "违反了 相邻的两个节点不为红色的规则" << endl;return false;}return _IsRBtree(root->_left, blacksize, k)&& _IsRBtree(root->_right, blacksize, k);}

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

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

相关文章

选对强大的技术底座:一篇文章讲透虚拟机与容器核心差异

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

mp4/图片转gif

mp4转gif ffmpeg -f gif -i name.gif output.mp4 ffmpeg -i output.mp4 -vf palettegen palette.png ffmpeg -i output.mp4 -i palette.png -lavfi paletteuse name.gif基于png图片生成调色板 ffpmpeg -i xx_Wait.gif …

详细介绍:09.【Linux系统编程】“文件“读写操作,Linux下一切皆文件!

详细介绍:09.【Linux系统编程】“文件“读写操作,Linux下一切皆文件!pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: …

数据类型-元组

元组(不可变类型):info = tuple()#空元组  info = (1,2,3,"guohan") 公共功能:1.索引:info[0] = 12.切片:info [0:3] = (1,2,3)3.步长:info [::2] = (1,3)4.for循环:for i in info:5.len: len(in…

深入解析:招聘:解决方案架构师 - 中国北京(混合办公)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

个人用云计算学习笔记 --14( Linux 逻辑卷管理、Linux 交换空间管理) - 教程

个人用云计算学习笔记 --14( Linux 逻辑卷管理、Linux 交换空间管理) - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-fa…

除了网页外 网站还需要东莞有哪些好企业

我一个朋友的网站&#xff0c;5月份时候被攻击了&#xff0c;然后他找我帮忙看看&#xff0c;我看他的网站、网上查资料&#xff0c;不看不知道&#xff0c;一看吓一跳&#xff0c;最近几年这网络安全形势真是不容乐观&#xff0c;在网上查了一下资料&#xff0c;1、中国信息通…

自然灾害vr学习机:山体滑坡+泥石流避险+洪涝逃生+地震逃生+台风避险+雷电避险 - 详解

自然灾害vr学习机:山体滑坡+泥石流避险+洪涝逃生+地震逃生+台风避险+雷电避险 - 详解2025-09-29 12:37 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; o…

站点搭建使用socket登陆wordpress源码

它是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 1 Spring 特点 轻量级控制反转面向切面容器框架集合 2 Spring 核心组件 3 Spring 常用模块 4 Spring 主要包 5 Spring 常用注解 bean…

小程序网站建站模板百度网址安全中心

全世界只有3.14 % 的人关注了青少年数学之旅科学是人类进步的阶梯&#xff01;在当今社会&#xff0c;科学技术的发展进步将为人类社会带来巨大的效益&#xff0c;毫不夸张的说&#xff0c;科学指引并推着着人类文明的进程。基础科学作为科学技术的理论基石&#xff0c;其重要性…

详细介绍:XXE - 实体注入(xml外部实体注入)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【面板材料】A股上市公司增发股票及配股相关资料(1991-2024年)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

BindingList的应用与改进

在编写UI的过程中,我们通常使用ObservableCollection来监听列表的变化。然而,ObservableCollection只能在添加/移动/移除元素时通知界面,这意味着元素内部更改时,ObservableCollection是无法通知的 如果需要监听列…

谷歌 SEO 新词 xx animate 等实操教程

如上图,最近 AI 圈又冒出新词:wan animate 等,你们都看到了吗? 今天聊聊 SEO 新词这个"淘金"生意,为什么有些词能做,有些词碰都不能碰。 一、wan animate vs veo3:天壤之别如上图:❌ veo3:打死别碰…

US$248 Xhorse VVDI2 BMW FEM/BDC + Copy 48 Transponder (96 Bit) + MQB Authorization

Xhorse VVDI2 BMW FEM/BDC + Copy 48 Transponder (96 Bit) + MQB Authorization Xhorse Promotion for loyal customers till Christmas!!! This is Authorization Only! No Need Shipping, please pass us serial nu…

完整教程:【读书笔记】架构整洁之道 P6 实现细节

完整教程:【读书笔记】架构整洁之道 P6 实现细节pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas",…

Print Conductor打印软件安装教程!一款非常好用的批量打印软件!支持PDF、Word、Excel、图片等

软件介绍 Print Conductor是一款由国外开发者制作的批量打印软件,支持PDF、Word、Excel、图片等多种格式文件的快速打印。它通过拖拽文件到软件界面即可实现批量打印,无需逐个打开文档,特别适合需要处理大量打印任务…

Python 面向对象编程基础:类与对象初体验

面向对象编程(OOP)是一种编程范式,它通过对象和类的概念来组织代码,使程序更加模块化、可维护和可扩展。Python 是一种支持面向对象编程的语言,提供了强大的类和对象机制。今天,就让我们一起学习 Python 中的面向…

Drools 7.0基础环境搭建

Drools 7.0基础环境搭建一、环境概述 Drools 7.0当前最新的是7.74.1 Final,Drools 8.0不兼容JDK8了(你发任你发,我用java8),7.73.0.Final这个兼容最稳定所以选这个 JDK:openjdk version "1.8.0_452" Mav…

o2o网站大全asp.net网站

系列文章目录 本系列课程主要针对于Ehcache缓存框架功能的开发实践全流程技术指南&#xff01; 第一节&#xff1a;Ehcache缓存框架的基本概念和简介第二节&#xff1a;Ehcache缓存框架的配置分析和说明第三节&#xff1a;Ehcache缓存框架的缓存方式的探索第四节&#xff1a;E…