红黑树:数据世界的平衡守护者

在 C++ 算法的神秘森林里,红黑树是一棵充满智慧的 “魔法树”。它既不像普通二叉搜索树那样容易失衡,也不像 AVL 树对平衡要求那么苛刻。作为 C++ 算法小白,今天就和大家一起深入探索红黑树的奥秘,看看它是如何成为数据世界的平衡守护者的!​

红黑树是什么?​

红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。通过对树的节点颜色进行约束,红黑树确保了树在最坏情况下,依然能保持相对平衡,从而让搜索、插入和删除操作的时间复杂度稳定在 ​

O(logn)

。​

红黑树的规则​

  1. 节点颜色:每个节点要么是红色,要么是黑色。​
  1. 根节点:根节点是黑色。​
  1. 叶子节点:每个叶子节点(NIL 节点,空节点)是黑色。​
  1. 红色节点:如果一个节点是红色的,那么它的两个子节点都是黑色的。​
  1. 路径黑色节点数:从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。​

这五条规则就像是红黑树的 “生存法则”,让它始终保持着良好的平衡状态。可以把红黑树想象成一个严格遵守交通规则的城市,不同颜色的节点如同不同类型的车辆,在规则的约束下有序行驶,确保城市不会陷入混乱。​

红黑树的实现​

在 C++ 中,我们可以通过定义节点结构和相关操作来实现红黑树。以下是一个简化版的红黑树实现代码,并对关键部分进行详细解释。​

节点结构定义​

#include <iostream>// 定义红黑树节点结构
struct RBNode {int key;bool color;  // true 表示红色,false 表示黑色RBNode* left;RBNode* right;RBNode* parent;RBNode(int k) : key(k), color(true), left(nullptr), right(nullptr), parent(nullptr) {}
};

每个节点包含键值 key 、颜色 color 、左右子节点指针 left 和 right ,以及父节点指针 parent 。节点默认颜色为红色,因为新插入节点为红色,在大多数情况下能减少调整操作。​

红黑树类定义与基本操作​

class RedBlackTree {
private:RBNode* root;// 左旋操作void leftRotate(RBNode* x) {RBNode* y = x->right;x->right = y->left;if (y->left != nullptr) {y->left->parent = x;}y->parent = x->parent;if (x->parent == nullptr) {root = y;} else if (x == x->parent->left) {x->parent->left = y;} else {x->parent->right = y;}y->left = x;x->parent = y;}// 右旋操作void rightRotate(RBNode* x) {RBNode* y = x->left;x->left = y->right;if (y->right != nullptr) {y->right->parent = x;}y->parent = x->parent;if (x->parent == nullptr) {root = y;} else if (x == x->parent->right) {x->parent->right = y;} else {x->parent->left = y;}y->right = x;x->parent = y;}// 插入节点后的修复操作void insertFixup(RBNode* z) {while (z != root && z->parent->color == true) {if (z->parent == z->parent->parent->left) {RBNode* y = z->parent->parent->right;if (y != nullptr && y->color == true) {z->parent->color = false;y->color = false;z->parent->parent->color = true;z = z->parent->parent;} else {if (z == z->parent->right) {z = z->parent;leftRotate(z);}z->parent->color = false;z->parent->parent->color = true;rightRotate(z->parent->parent);}} else {RBNode* y = z->parent->parent->left;if (y != nullptr && y->color == true) {z->parent->color = false;y->color = false;z->parent->parent->color = true;z = z->parent->parent;} else {if (z == z->parent->left) {z = z->parent;rightRotate(z);}z->parent->color = false;z->parent->parent->color = true;leftRotate(z->parent->parent);}}}root->color = false;}public:RedBlackTree() : root(nullptr) {}// 插入节点void insert(int key) {RBNode* z = new RBNode(key);RBNode* y = nullptr;RBNode* x = root;while (x != nullptr) {y = x;if (z->key < x->key) {x = x->left;} else {x = x->right;}}z->parent = y;if (y == nullptr) {root = z;} else if (z->key < y->key) {y->left = z;} else {y->right = z;}insertFixup(z);}// 中序遍历void inorderTraversal(RBNode* node) {if (node != nullptr) {inorderTraversal(node->left);std::cout << node->key << " ";inorderTraversal(node->right);}}void inorderTraversal() {inorderTraversal(root);std::cout << std::endl;}
};
  1. 旋转操作:左旋 leftRotate 和右旋 rightRotate 是红黑树保持平衡的重要手段。左旋以某个节点 x 为中心,将其右子节点 y 提升,x 变为 y 的左子节点;右旋则相反。就像在玩积木时,通过旋转积木块来调整结构,让树重新达到平衡。​
  1. 插入修复操作:insertFixup 函数在插入新节点后,根据红黑树规则进行调整。如果新插入节点的父节点是红色,就可能违反规则,需要通过变色和旋转操作来修复,确保树满足所有红黑树规则。​
  1. 插入节点:insert 函数先按照普通二叉搜索树的方式找到插入位置,插入新节点后调用 insertFixup 进行修复,维持红黑树的平衡。​
  1. 中序遍历:inorderTraversal 函数用于遍历红黑树,按顺序输出节点的键值,方便查看树的结构和内容。​

例题讲解:使用红黑树实现动态数据集合管理​

问题描述​

假设我们需要管理一个动态的整数集合,要求能够快速插入新元素,并按顺序输出集合中的所有元素。使用红黑树来实现这个功能。​

代码示例​

int main() {RedBlackTree rbt;rbt.insert(5);rbt.insert(3);rbt.insert(7);rbt.insert(2);rbt.insert(4);rbt.insert(6);rbt.insert(8);std::cout << "Inorder traversal of the Red-Black Tree: ";rbt.inorderTraversal();return 0;
}

代码解释​

在 main 函数中,创建了一个红黑树对象 rbt ,然后依次插入多个整数。插入过程中,红黑树会自动调整结构,保持平衡。最后通过中序遍历,按顺序输出红黑树中的所有节点键值,得到有序的整数集合。​

红黑树在很多场景都有重要应用,比如 C++ 标准库中的 map 和 set ,底层实现就用到了红黑树。它凭借高效的平衡维护和稳定的时间复杂度,成为了数据管理的得力助手。作为 C++ 算法小白,掌握红黑树的原理和应用,能让我们在算法学习和编程实践中更上一层楼!

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

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

相关文章

【hot100-动态规划-139.单词拆分】

力扣139.单词拆分 本题要求判断给定的字符串 s 是否可以被空格拆分为一个或多个在字典 wordDict 中出现的单词,且不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用,这是一个典型的动态规划问题。 动态规划思路 定义状态: 定义一个布尔类型的数组 dp,其中…

ZFile与Cpolar技术结合实现远程数据实时访问与集中管理的可行性分析

文章目录 前言1.关于ZFile2.本地部署ZFile3.ZFile本地访问测试4.ZFile的配置5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定ZFile公网地址 前言 在信息爆炸的年代&#xff0c;每个现代人都在数字浪潮中扮演着独特的角色。不论是商务精英、影像创作者还是学术达人&…

Vue2在子组件上使用v-model实现数据的双向绑定、.sync修饰符

1、v-model 先看示例&#xff1a; //父组件<template><ChildComponent v-model"parentData" /> </template><script> import ChildComponent from ./ChildComponent.vue;export default {components: {ChildComponent},data() {return {pa…

自学嵌入式 day 18 - 数据结构 1

数据结构 相互之间存在一种或多种特定关系的数据元素的集合 1.特定关系&#xff1a; &#xff08;1&#xff09;逻辑结构&#xff1a; ①集合&#xff1a;所有在同一个集合中&#xff0c;关系平等。 ②线性关系&#xff1a;数据和数据之间是一对一的关系。&#xff08;数组…

《Java 大视界——Java 大数据在智能电网分布式能源协同调度中的应用与挑战》

随着风电、光伏等分布式能源大规模接入电网&#xff0c;传统调度系统面临数据规模激增、响应延迟显著、多源异构数据融合困难等核心问题。本文聚焦Java生态下的大数据技术体系&#xff0c;深入探讨其在智能电网实时监测、负荷预测、资源优化配置等场景中的落地实践。通过分析Sp…

解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs-MCP大模型上下文解析

解密企业级大模型智能体Agentic AI 关键技术&#xff1a;MCP、A2A、Reasoning LLMs-MCP大模型上下文解析 我们首先来看一下 整个MCP的一个基本的一个流程&#xff0c;他解决的一个问题。我们回到这里&#xff0c;他解决的一个问题是什么呢&#xff1f;他解决这个问题就是你的大…

25.5.15

没有比水题更令人开心的事情了 典型的并查集题目&#xff0c;并查集分为并和查&#xff0c;并就是把有关系的父亲根结点设为同一个&#xff0c;查就是在成功构造后对其进行查询 查通过递归实现 if (x f[x])return x; return f[x] find(f[x]); 由于并查集的特点&#xff0…

低损耗高效能100G O Band DWDM 10km光模块 | 支持密集波分复用

目录 前言 一、产品概述 100G QSFP28 O Band DWDM 10km光模块核心特点包括&#xff1a; 二、为何选择O Band DWDM方案&#xff1f; 1.低色散损耗&#xff0c;传输更稳定 2.兼容性强 三、典型应用场景 1.数据中心互联&#xff08;DCI&#xff09; 2.企业园区/智慧城市组网 3.电信…

CentOS 7 内核升级指南:解决兼容性问题并提升性能

点击上方“程序猿技术大咖”&#xff0c;关注并选择“设为星标” 回复“加群”获取入群讨论资格&#xff01; CentOS 7 默认搭载的 3.10.x 版本内核虽然稳定&#xff0c;但随着硬件和软件技术的快速发展&#xff0c;可能面临以下问题&#xff1a; 硬件兼容性不足&#xff1a;新…

计算机视觉----基础概念、卷积

一、概述 1.计算机视觉的定义 计算机视觉(Computer Vision)是一个跨学科的研究领域,主要涉及如何使计算机能够通过处理和理解数字图像或视频来自动进行有意义的分析和决策。其目标是使计算机能够从视觉数据中获取高层次的理解,类似于人类的视觉处理能力。 具体来说,计算机…

2025认证杯数学建模第二阶段C题:化工厂生产流程的预测和控制,思路+模型+代码

2025认证杯数学建模第二阶段思路模型代码&#xff0c;详细内容见文末名片 一、探秘化工世界&#xff1a;问题背景大揭秘 在 2025 年 “认证杯”数学中国数学建模网络挑战赛第二阶段 C 题中&#xff0c;我们一头扎进了神秘又复杂的化工厂生产流程预测与控制领域。想象一下&…

关于AI人工智能的知识图谱简介

人工智能是计算机科学的一个重要领域&#xff0c;旨在理解和构建智能行为。人工智能可以被划分为多个子领域或分支&#xff0c;包括机器学习、深度学习、自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;、计算机视觉&#xff08;Computer Vis…

巧妙利用redis防爆破

爆破&#xff0c;也就是通过海量的尝试&#xff0c;最终确定密码&#xff0c;人们设置密码具有习惯性&#xff0c;好记、简单、有象征等&#xff0c;也就有密码字典一说&#xff0c;但是该字典也是巨量的&#xff0c;但是相对于各种字母符号等组合就显得轻量非常多 在Java Spr…

Uniapp开发鸿蒙购物项目教程之样式选择器

大家好&#xff0c;今天依然为大家带来鸿蒙跨平台开发教程的分享&#xff0c;我们本系列的教程最终要做一个购物应用&#xff0c;通过这个项目为大家分享uniapp开发鸿蒙应用从配置开发环境到应用打包上架的完成过程。 昨天的文章实现了应用首页的轮播图&#xff0c;其中涉及到…

2、ubantu系统配置OpenSSH | 使用vscode或pycharm远程连接

1、OpenSSH介绍 OpenSSH&#xff08;Open Secure Shell&#xff09;是一套基于SSH协议的开源工具&#xff0c;用于在计算机网络中提供安全的加密通信。它被广泛用于远程系统管理、文件传输和网络服务的安全隧道搭建&#xff0c;是保护网络通信免受窃听和攻击的重要工具。 1.1…

Leetcode刷题 | Day63_图论08_拓扑排序

一、学习任务 拓扑排序代码随想录 二、具体题目 1.拓扑排序117. 软件构建 【题目描述】 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依…

uniapp中vue3和pinia安装依赖npm install失败

目录 一、问题描述 二、问题原因 三、问题解析及解决方案 一、问题描述 用uni-app开发小程序的时候&#xff0c;使用了vue3pinia,安装依赖的时候发现vue和pinia的版本问题&#xff0c;安装失败&#xff0c; npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve np…

2025认证杯第二阶段数学建模B题:谣言在社交网络上的传播思路+模型+代码

2025认证杯数学建模第二阶段思路模型代码&#xff0c;详细内容见文末名片 一、引言 在当今数字化时代&#xff0c;社交网络已然成为人们生活中不可或缺的一部分。信息在社交网络上的传播速度犹如闪电&#xff0c;瞬间就能触及大量用户。然而&#xff0c;这也为谣言的滋生和扩…

【C#】Thread.Join()、异步等待和直接join

JogThread.Join() 是 .NET 中 System.Threading.Thread 类的一个方法&#xff0c;用来让当前调用线程暂停执行&#xff0c;直到目标线程&#xff08;这里是 JogThread&#xff09;终止为止。以下是它的核心语义和你在 UI 代码里需要注意的几个相关知识点。 1. Thread.Join() 的…

牛客网NC22012:判断闰年问题详解

牛客网NC22012&#xff1a;判断闰年问题详解 &#x1f4dd; 题目描述 题号&#xff1a;NC22012&#xff08;牛客网&#xff09; 时间限制&#xff1a;C/C/Rust/Pascal 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C/Rust/Pascal 32 M&#xff0c;其他语言64 M 判断一个…