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

使用c++实现红黑树的构建和插入

1.红黑树简介:

红黑树实际上和AVL都属于一棵用于存储数据的平衡二叉搜索树,但是这棵树并不是使用平衡因子去维持平衡的,而是结合限制条件对结点标红标黑去让树达到类似平衡的效果。

2.红黑树的限制条件和效率分析:

2.1限制条件

1. 每个结点不是红⾊就是⿊⾊
2. 根结点是⿊⾊的
3. 如果⼀个结点是红⾊的,则它的两个孩⼦结点必须是⿊⾊的,也就是说任意⼀条路径不会有连续的
红⾊结点。
4. 对于任意⼀个结点,从该结点到其所有NULL结点的简单路径上,均包含相同数量的⿊⾊结点

2.2效率分析

由规则四可以知道每条路径上的黑结点个数相同,那么在极端情况下,最短路径就是全黑,最长路径就是一黑一红,设最短路径长度为h,最长则为2h,2^{h}-1<N<2^{2h}-1,推导可得h基本上就是为一个logn,说明在插入的时候最差的时间复杂度也就为接近2*logn。

3.红黑树构建时的准备:

3.1红黑标记:

3.2红黑树的结点结构设计:

这里每个结点默认都是处理为红色,因为如果你处理成黑色的话,那当别的地方要处理成红色的时候,别的地方要保持规则四就很困难了,因为这个存储结构是一棵树。

3.3红黑树的结构设计:

template<class K, class V>
class rb_tree {typedef rb_tree_node<K,V> node;
private:node* root_=nullptr;
};

基本上和AVL树很类似。

3.4处理前的插入:

bool insert(const pair<K, V>& kv) {if (root_ == nullptr) {root_ = new node(kv);root_->col = BLACK;//规定的根为黑色return true;}node* cur = root_;//这部分就和别的二叉搜索树一致node* parent = root_;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);if (parent->kv_.first > kv.first) {parent->left = cur;}else {parent->right = cur;}cur->parent = parent;

4.对违反规则的地方进行处理:

4.1情况1:

当插入x时,因为红色的子结点必须是黑色的,所以需要进行处理,如果他的叔叔结点是红色的,那么无论他是在6还是15插入,只需要把它的叔叔结点和父亲结点变为黑色,然后再把它的父亲变为红色。那么就能保证规则不被破坏,每条路的黑结点个数都相同。这里并不是就是结束!当变为红色的时候,可能导致上面的规则遭到破坏,也就是它的上方可能是红色的,那么它也得进行类似的处理。

4.2情况2:

当插入位置为在cur且叔叔为黑色或者不存在的时候,通过这样处理之后可以让规则得到满足。也就是进行一次右单选再与情况1进行相同方式的变色。

4.3情况3:

当cur位置为在cur且叔叔为黑色或者不存在的时候,通过这样处理之后可以让规则得到满足。也就是进行一次左单选再右单旋最后与情况1进行相同方式的变色。


这里还存在一种特殊情况,就是有可能根结点会被处理成红色,但是,根结点实际上是不会影响分路上黑结点分布相同的。所以最后只需要把根结点也处理成黑色就能保证规则不会出现问题。

通过这三种情况就能够把所有情况给包含进去了。

4.4代码展示:

	while (parent && parent->col == RED) {//node* grandfather = parent->parent;if (grandfather->left == parent) {//处理左子树if (grandfather->right && grandfather->right->col == RED) {//叔是红色parent->col = BLACK;//变色grandfather->right->col = BLACK;grandfather->col = RED;cur = grandfather;//往上接着迭代parent = grandfather->parent;}else {//叔叔不存在或者叔叔为黑色if (cur == parent->left) {//只需要单旋就能解决rotateR(grandfather);grandfather->col = RED;parent->col = BLACK;}else {//需要双旋才能解决rotateL(parent);rotateR(grandfather);grandfather->col = RED;parent->col = BLACK;}break;}}else {if (grandfather->left&&grandfather->left->col == RED) {//叔是红色parent->col = BLACK;//变色grandfather->left->col = BLACK;grandfather->col = RED;cur = grandfather;//往上接着迭代parent = grandfather->parent;}else {//叔叔不存在或者叔叔为黑色if (cur == parent->right) {//只需要单旋就能解决rotateL(grandfather);grandfather->col = RED;parent->col = BLACK;}else {//需要双旋才能解决rotateR(parent);rotateL(grandfather);grandfather->col = RED;parent->col = BLACK;}break;}}}root_->col = BLACK;//最后记得把根结点的颜色变为黑色return true;
}

5.完整代码展示:

#include <iostream>
using namespace std;
enum color {RED,BLACK
};
template<class K,class V>
class rb_tree_node {
public:rb_tree_node(const pair<K, V>& kv) :kv_(kv), right(nullptr), left(nullptr), parent(nullptr), col (RED){}rb_tree_node* right;rb_tree_node* left;rb_tree_node* parent;pair<K, V> kv_;color col;
};
template<class K, class V>
class rb_tree {typedef rb_tree_node<K,V> node;
public:bool insert(const pair<K, V>& kv) {if (root_ == nullptr) {root_ = new node(kv);root_->col = BLACK;return true;}node* cur = root_;node* parent = root_;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);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;if (grandfather->left == parent) {if (grandfather->right && grandfather->right->col == RED) {//叔是红色parent->col = BLACK;//变色grandfather->right->col = BLACK;grandfather->col = RED;cur = grandfather;//往上接着迭代parent = grandfather->parent;}else {//叔叔不存在或者叔叔为黑色if (cur == parent->left) {//只需要单旋就能解决rotateR(grandfather);grandfather->col = RED;parent->col = BLACK;}else {//需要双旋才能解决rotateL(parent);rotateR(grandfather);grandfather->col = RED;parent->col = BLACK;}break;}}else {if (grandfather->left&&grandfather->left->col == RED) {//叔是红色parent->col = BLACK;//变色grandfather->left->col = BLACK;grandfather->col = RED;cur = grandfather;//往上接着迭代parent = grandfather->parent;}else {//叔叔不存在或者叔叔为黑色if (cur == parent->right) {//只需要单旋就能解决rotateL(grandfather);grandfather->col = RED;parent->col = BLACK;}else {//需要双旋才能解决rotateR(parent);rotateL(grandfather);grandfather->col = RED;parent->col = BLACK;}break;}}}root_->col = BLACK;return true;}void rotateR(node* parent) {node* sub_L = parent->left;node* sub_LR = sub_L->right;parent->left = sub_LR;if (sub_LR) {sub_LR->parent = parent;}sub_L->right = parent;if (parent == root_) {root_ = sub_L;}node* ppnode;ppnode = parent->parent;if (ppnode) {if (ppnode->right == parent) {ppnode->right = sub_L;}else {ppnode->left = sub_L;}}parent->parent = sub_L;}void rotateL(node* parent) {node* sub_R = parent->right;node* sub_RL = sub_R->left;parent->right = sub_RL;if (sub_RL) {sub_RL->parent = parent;}sub_R->left = parent;if (parent == root_) {root_ = sub_R;}node* ppnode;ppnode = parent->parent;if (ppnode) {if (ppnode->right == parent) {ppnode->right = sub_R;}else {ppnode->left = sub_R;}}parent->parent = sub_R;}void inorder() {inorder_(root_);}
private:void inorder_(node* root) {if (root == nullptr) {return;}inorder_(root->left);cout << root->kv_.first <<" ";inorder_(root->right);}node* root_=nullptr;
};
int main() {rb_tree<int, int>tree1;tree1.insert({ 2,2 });tree1.insert({ 3,2 });tree1.insert({ 1,2 });tree1.insert({ 5,2 });tree1.insert({ 4,2 });tree1.insert({ 6,2 });tree1.inorder();return 0;
}


 

相关文章:

使用c++实现红黑树的构建和插入

1.红黑树简介&#xff1a; 红黑树实际上和AVL都属于一棵用于存储数据的平衡二叉搜索树&#xff0c;但是这棵树并不是使用平衡因子去维持平衡的&#xff0c;而是结合限制条件对结点标红标黑去让树达到类似平衡的效果。 2.红黑树的限制条件和效率分析&#xff1a; 2.1限制条件…...

在大型语言模型(LLM)框架内Transformer架构与混合专家(MoE)策略的概念整合

文章目录 传统的神经网络框架存在的问题一. Transformer架构综述1.1 transformer的输入1.1.1 词向量1.1.2 位置编码&#xff08;Positional Encoding&#xff09;1.1.3 编码器与解码器结构1.1.4 多头自注意力机制 二.Transformer分步详解2.1 传统词向量存在的问题2.2 详解编解码…...

Jenkins项目CICD流程

Jenkins项目流程:1.配置git环境 git config --...2.把前后端的目录初始化位本地工作目录 #git init3.提交到本地git #git add ./ git commit -m "" git tag v14.然后提交到远程git(通过,用户,群组,项目,管理项目)git remote add origin http://...git push -…...

【IDEA】2017版本的使用

目录 一、常识 二、安装 1. 下载IDEA2017.exe 2. 安装教程 三、基本配置 1. 自动更新关掉 2. 整合JDK环境 3. 隐藏.idea文件夹和.iml等文件 四、创建Java工程 1. 新建项目 2. 创建包结构&#xff0c;创建类&#xff0c;编写main主函数&#xff0c;在控制台输出内容。…...

Git指南-从入门到精通

代码提交和同步命令 流程图如下&#xff1a; 第零步: 工作区与仓库保持一致第一步: 文件增删改&#xff0c;变为已修改状态第二步: git add &#xff0c;变为已暂存状态 bash $ git status $ git add --all # 当前项目下的所有更改 $ git add . # 当前目录下的所有更改 $ g…...

Spring boot(maven) - Mybatis 超级入门版

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…...

Spark 性能优化 (三):RBO 与 CBO

1. RBO 的核心概念 在 Apache Spark 的查询优化过程中&#xff0c;规则优化&#xff08;Rule-Based Optimization, RBO&#xff09; 是 Catalyst 优化器的一个关键组成部分。它主要依赖于一组固定的规则进行优化&#xff0c;而不是基于统计信息&#xff08;如 CBO - Cost-Base…...

读 DeepSeek-R1 论文笔记

DeepSeek-R1&#xff1a;通过强化学习激发大语言模型的推理能力 DeepSeek-AI 摘要 我们推出第一代推理模型DeepSeek-R1-Zero和DeepSeek-R1。DeepSeek-R1-Zero作为无需监督微调(SFT)预训练阶段、直接通过大规模强化学习(RL)训练的基础模型&#xff0c;展现出卓越的推理能力。…...

【Android开发AI实战】选择目标跟踪基于opencv实现——运动跟踪

文章目录 【Android 开发 AI 实战】选择目标跟踪基于 opencv 实现 —— 运动跟踪一、引言二、Android 开发与 AI 的融合趋势三、OpenCV 简介四、运动跟踪原理&#xff08;一&#xff09;光流法&#xff08;二&#xff09;卡尔曼滤波&#xff08;三&#xff09;粒子滤波 五、基于…...

Eclipse JSP/Servlet 深入解析

Eclipse JSP/Servlet 深入解析 引言 随着互联网的快速发展,Java Web开发技术逐渐成为企业级应用开发的主流。在Java Web开发中,JSP(JavaServer Pages)和Servlet是两个核心组件,它们共同构成了Java Web应用程序的基础。本文将深入解析Eclipse平台下的JSP/Servlet技术,帮…...

申论概括类【2021副省第二题“局区合一”】

材料&#xff1a; “李总监&#xff0c;您好&#xff0c;我是芯谷产业功能区项目投资科的小罗&#xff0c;从今天开始&#xff0c;我就是你们公司的项目专员&#xff0c;以后有什么问题您都可以找我。”W光学有限公司总务部总监李晓枫接到小罗的电话时&#xff0c;既意外又暖心…...

如何保持长久无痛苦的学英语?

“无痛苦”学英语&#xff1f; 听起来像天方夜谭&#xff0c;但并非不可能&#xff01; 关键在于&#xff0c;把英语学习变成你生活的一部分&#xff0c;融入你的兴趣和目标&#xff0c; 这样才能摆脱痛苦&#xff0c;享受学习的过程。 1. 兴趣是最好的老师&#xff1a; 找到自…...

SQL-leetcode—1661. 每台机器的进程平均运行时间

1661. 每台机器的进程平均运行时间 表: Activity ----------------------- | Column Name | Type | ----------------------- | machine_id | int | | process_id | int | | activity_type | enum | | timestamp | float | ----------------------- 该表展示了一家工厂网站的…...

Linux例行任务:at 、cron、 /etc/contain 辨析

文章目录 一、at&#xff1a;一次性任务调度1. **基本用法**2. **管理任务**3. **权限控制** 二、cron&#xff1a;周期性任务调度1. **用户级任务**2. **系统级任务**3. **特殊字符串**4. **权限控制**5. **环境问题** 三、容器环境中的例行任务1. **在容器内运行 cron**2. **…...

Vue2中常用指令

文章目录 Vue2中常用指令1. v-text 动态渲染纯文本内容1. 作用2. 基本用法3. 示例4. 注意事项 2. v-html 动态渲染 HTML 内容1. 作用2. 基本用法3. 示例4. 注意事项 3. v-bind 动态绑定 HTML 属性1. 作用2. 基本用法3. 示例4. 注意事项5. 绑定class属性的用法6. 绑定style属性的…...

Sequence to Sequence model

基础模型 基础模型是用RNN模型&#xff0c;前部分是encoder用来寻找法语输入的编码&#xff0c;后半部分是decoder用来生成英文翻译作为输出&#xff0c;每次输出一个单词&#xff0c;直到输出结束标志如EOS。 下面是另一个例子&#xff0c;在CNN模型输出层之前会输出图片的向…...

PHP 超级全局变量

PHP 超级全局变量 引言 在PHP编程中&#xff0c;超级全局变量&#xff08;Superglobals&#xff09;是一类特殊的变量&#xff0c;它们在任何函数、类或文件中都可以访问。这些变量在PHP的全局作用域中始终可用&#xff0c;为开发者提供了处理HTTP请求和响应的强大工具。本文…...

如何在Vscode中接入Deepseek

在VS Code&#xff08;Visual Studio Code&#xff09;中接入DeepSeek&#xff0c;可以按照以下步骤进行操作&#xff1a; 一、准备工作 确保VS Code为最新版本&#xff1a; DeepSeek可能依赖于VS Code的某些最新功能或修复&#xff0c;因此建议先将VS Code更新到最新版本。注…...

6.appender

文章目录 一、前言二、源码解析AppenderUnsynchronizedAppenderBaseOutputStreamAppenderConsoleAppenderFileAppenderRollingFileAppenderFileNamePattern 三、总结 一、前言 前一篇文章介绍了appender、conversionRule、root和logger节点的解析, 为的是为本篇详细介绍它们的…...

Golang的消息队列架构

一、消息队列的定义和作用 消息队列是一种在不同组件之间传递消息的通信机制。它可以解耦系统的各个部分&#xff0c;提高系统的可靠性和扩展性。消息队列可以在系统之间传递消息&#xff0c;并且在消息发送者和消息接收者之间进行异步通信&#xff0c;使得系统可以更加灵活和高…...

如何在Servlet容器中使用HttpServletResponse?

HttpServletResponse 是 Java Servlet API 中的一个接口&#xff0c;它代表了服务器对客户端的响应。通过 HttpServletResponse 对象&#xff0c;可以设置响应的状态码、发送数据到客户端&#xff08;如 HTML 页面、文件等&#xff09;、添加响应头信息等。下面是如何在 Servle…...

DeepSeek自然语言处理(NLP)基础与实践

自然语言处理(Natural Language Processing, NLP)是人工智能领域的一个重要分支,专注于让计算机理解、生成和处理人类语言。NLP技术广泛应用于机器翻译、情感分析、文本分类、问答系统等场景。DeepSeek提供了强大的工具和API,帮助我们高效地构建和训练NLP模型。本文将详细介…...

GESP5级语法知识(十一):高精度算法(一)

高精度加法&#xff1a; #include<iostream> #include<string> #include<algorithm> using namespace std; const int N501;//高精度数的最长长度 //c[]a[]b[]:高精度加法方案一&#xff1a;对应位相加&#xff0c;同时处理进位 void h_add_1(int a[],int b…...

【前端】 react项目使用bootstrap、useRef和useState之间的区别和应用

一、场景描述 我想写一个轮播图的程序&#xff0c;只是把bootstrap里面的轮播图拉过来就用上感觉不是很合适&#xff0c;然后我就想自己写自动轮播&#xff0c;因此&#xff0c;这篇文章里面只是自动轮播的部分&#xff0c;没有按键跟自动轮播的衔接部分。 Ps: 本文用的是函数…...

PYYAML反序列化详解

前言 最近看了很多pyyaml反序列化的漏洞利用&#xff0c;但是对漏洞怎么来的&#xff0c;没有进行很详细的分析&#xff0c;所以今天刚好学习一下反序列化的原理 Yaml基本语法 一个 .yml 文件中可以有多份配置文件&#xff0c;用 --- 隔开即可对大小写敏感YAML 中的值&#x…...

【离散数学上机】T235,T236

T235题目&#xff1a;输入集合A和B&#xff0c;输出A到B上的所有单射函数。 问题描述 给定非空数字集合A和B&#xff0c;求出集合A到集合B上的所有单射函数。 输入格式 第一行输入m和n&#xff08;空格间隔&#xff09;&#xff0c;分别为集合A和集合B中的元素个数&#xff1b;…...

LeeCode题库第十八题

项目场景&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&…...

Zookeeper 和 Redis 哪种更好?

目录 前言 &#xff1a; 什么是Zookeeper 和 Redis &#xff1f; 1. 核心定位与功能 2. 关键差异点 (1) 一致性模型 (2) 性能 (3) 数据容量 (4) 高可用性 3. 适用场景 使用 Zookeeper 的场景 使用 Redis 的场景 4. 替代方案 5. 如何选择&#xff1f; 6. 常见误区 7. 总结 前言…...

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_localtime 函数

ngx_localtime 函数 声明 在 src\os\unix\ngx_time.h 中&#xff1a; void ngx_localtime(time_t s, ngx_tm_t *tm); 定义 在 src/os/unix/ngx_time.c 中 void ngx_localtime(time_t s, ngx_tm_t *tm) { #if (NGX_HAVE_LOCALTIME_R)(void) localtime_r(&s, tm);#elsengx_tm…...

SpringBoot初始化8个常用方法

在 Spring Boot 中&#xff0c;初始化方法通常是在应用程序启动时被调用的&#xff0c;可以用来执行应用启动时的一些准备工作。以下是几种常见的初始化方法&#xff1a; 一、顺序 1. 图解 ┌─────────────────────────────┐│ Spring Boot…...