【C/C++】红黑树学习笔记

文章目录

  • 红黑树
    • 1 基本概念
      • 1.1 定义
      • 1.2 基本特性推理
      • 1.3 对比
      • 1.4 延伸
        • 1.4.1 简单判别是否是红黑树
        • 1.4.2 应用
    • 2 插入
      • 2.1 插入结点默认红色
      • 2.2 插入结点
        • 2.2.1 插入结点是根结点
        • 2.2.2 插入结点的叔叔是红色
        • 2.2.3 插入结点的叔叔是黑色
          • 场景分析
            • LL型
            • RR型
            • LR型
            • RL型
    • 3 构建
    • 4 示例代码

红黑树

1 基本概念

1.1 定义

红黑树首先是二叉搜索树(左<根<右);
基本性质:

  1. 结点非红即黑;
  2. 根/叶子都是黑;
  3. 任意节点向下的所有路径上存在黑结点数量一致;
  4. 红结点下不能直连红结点;

1.2 基本特性推理

  • 最长路径不超过最短路径的两倍;

1.3 对比

与AVL树对比:

AVLRB
高度任一结点左右子树的高度差绝对值不超过1任一结点左右子树的高度差不超过两倍
查询效率(相对)稍高 O(lg n)稍低 O(lg n)
插入/删除效率(相对)

1.4 延伸

1.4.1 简单判别是否是红黑树
1
4
10
13
17
19
25
28
31
  • 答案:否
    • 如果添加NIL结点,发现某一结点下路径的黑结点数量并不相同
1.4.2 应用
  • c++ stl中的map/set 是基于红黑树实现的

2 插入

2.1 插入结点默认红色

  • 如果默认黑色,首先就会破坏黑高同原则,调整相对比较麻烦;
  • 默认红色,可能破坏不红红原则或根为黑原则,调整相对容易;

2.2 插入结点

如果红黑树性质被破坏,分三种情况调整:

2.2.1 插入结点是根结点
  • 违反根为黑原则
  • 调整方案:直接变黑
2.2.2 插入结点的叔叔是红色

示例1:插入结点1

1
5
7
8

调整方案:

  • father 和 uncle 变红,grandpather 变黑
  • grandfather变为插入结点,继续判断是否违反原则
1
5
7
8
2.2.3 插入结点的叔叔是黑色

示例:插入结点1

1
5
7
该情况下,uncle可能直观上不存在,但是红黑树默认有NIL结点,是黑的

调整方案:

  • 根据不同场景(LL/LR/RR/RL)进行旋转,然后变色
场景分析
LL型
1
5
7
NULL

step 1:基于grandfather右旋

1
5
7

step 2:变色

1
5
7
RR型

在这里插入图片描述

step 1:基于grandfather进行左旋
在这里插入图片描述
step 2:变色
在这里插入图片描述

LR型

在这里插入图片描述
调整方案:
在这里插入图片描述

RL型

在这里插入图片描述
调整方案:
在这里插入图片描述

3 构建

按照二叉搜索树规则,依次插入结点,并根据插入规则进行调整

4 示例代码

根据算法导论伪代码实现:

#pragma once#include <iostream>
#include <functional>enum Color {RED, BLACK};struct RBNode {int key;Color color;RBNode *left;RBNode *right;RBNode *parent;
};class RBTree {
private:RBNode *root;RBNode *NIL;void LeftRotate(RBNode *x) {RBNode *y = x->right;x->right = y->left;if (x->right != NIL) {x->right->parent = x;}y->parent = x->parent;if (x->parent == NIL) {root = y;} else if (x == x->parent->left) {x->parent->left = y;} else {x->parent->right = y;}x->parent = y;y->left = x;}void RightRotate(RBNode *y) {RBNode *x = y->left;y->left = x->right;if (y->left != NIL) {y->left->parent = y;}x->parent = y->parent;if (y->parent == NIL) {root = x;} else if (y->parent->left = y) {y->parent->left = x;} else {y->parent->right = x;}y->parent = x;x->right = y;}void InsertFixup(RBNode *z) {while (z->parent->color == RED) {if (z->parent == z->parent->parent->left) {RBNode *y = z->parent->parent->right;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->right) {z = z->parent;LeftRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;RightRotate(z->parent->parent);}} else {RBNode *y = z->parent->parent->left;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->left) {z = z->parent;RightRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;LeftRotate(z->parent->parent);}}}root->color = BLACK;}void Transplant(RBNode *u, RBNode *v) {if (u->parent == NIL) {root = v;} else if (u == u->parent->left) {u->parent->left = v;} else {u->parent->right = v;}v->parent = u->parent; // if v is nullptr or NIL}void DeleteFixup(RBNode *x) {while (x != root && x->color == BLACK) {if (x == x->parent->left) {RBNode *w = x->parent->right;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;LeftRotate(x->parent);w = x->parent->right;}if (w->left->color == BLACK && w->right->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->right->color == BLACK) {w->left->color = BLACK;w->color = RED;RightRotate(w);w = x->parent->right;}w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;LeftRotate(x->parent);x = root;}} else {RBNode *w = x->parent->left;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;RightRotate(x->parent);w = x->parent->left;}if (w->right->color == BLACK && w->left->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->left->color == BLACK) {w->right->color = BLACK;w->color = RED;LeftRotate(w);w = x->parent->left;}w->color = x->parent->color;x->parent->color = BLACK;w->left->color = BLACK;RightRotate(x->parent);x = root;}}}x->color = BLACK;}RBNode* Minimum(RBNode *node) {while (node->left != NIL) {node = node->left;}return node;}public:RBTree() {NIL = new RBNode{0, BLACK, nullptr, nullptr, nullptr};root = NIL;}~RBTree() {std::function<void(RBNode *)> deleteNode = [&](RBNode *node) {if (node != NIL) {deleteNode(node->left);deleteNode(node->right);delete node;}};deleteNode(root);delete NIL;}void Insert(int key) {RBNode *z = new RBNode{key, RED, NIL, NIL};RBNode *y = NIL;RBNode *x = root;while (x != NIL) {y = x;if (z->key < x->key) {x = x->left;} else {x = x->right;}}z->parent = y;if (y == NIL) {root = z;} else if (z->key < y->key) {y->left = z;} else {y->right = z;}InsertFixup(z);}void Remove(int key) {RBNode *z = root;while (z != NIL && z->key != key) {if (key < z->key) {z = z->left;} else {z = z->right;}}if (z == NIL) {return;}RBNode *y = z;RBNode *x;Color yOriColor = y->color;if (z->left == NIL) {x = z->right;Transplant(z, z->right);} else if (z->right == NIL) {x = z->left;Transplant(z, z->left);} else {y = Minimum(z->right);yOriColor = y->color;x = y->right;if (y->parent == z) {x->parent = y;} else {Transplant(y, y->right);y->right = z->right;y->right->parent = y;}Transplant(z, y);y->left = z->left;y->left->parent = y;y->color = z->color;}delete z;if (yOriColor == BLACK) {DeleteFixup(x);}}void Inorder() {InorderHelper(root);std::cout << std::endl;}void InorderHelper(RBNode* node) {if (node != NIL) {InorderHelper(node->left);std::cout << node->key << " (" << (node->color == RED ? "R)" : "B)") << " ";InorderHelper(node->right);}}
};

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

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

相关文章

网络通信的基石:深入理解帧与报文

在这个万物互联的时代&#xff0c;我们每天都在享受着网络带来的便利——从早晨查看天气预报&#xff0c;到工作中的视频会议&#xff0c;再到晚上刷着短视频放松。然而&#xff0c;在这些看似简单的网络交互背后&#xff0c;隐藏着精密而复杂的数据传输机制。今天&#xff0c;…

STM32 SPI通信(硬件)

一、SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担 可配置8位/16位数据帧、高位先行/低位先行 时钟频率&#xff1a; fPCLK / (2, 4, 8, 16, 32, 64, 128, 256) 支持多主机模型、主或从操作 可…

尚硅谷redis7-11-redis10大类型之总体概述

前提&#xff1a;我们说的数据类型一般是value的数据类型&#xff0c;key的类型都是字符串。 redis字符串【String】 string类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。 string类型是Redis最基本的数据类型,一个redis中字符串va…

【递归、搜索与回溯算法】专题一 递归

文章目录 0.理解递归、搜索与回溯1.面试题 08.06.汉诺塔问题1.1 题目1.2 思路1.3 代码 2. 合并两个有序链表2.1 题目2.2 思路2.3 代码 3.反转链表3.1 题目3.2 思路3.3 代码 4.两两交换链表中的节点4.1 题目4.2 思路4.3 代码 5. Pow(x, n) - 快速幂5.1 题目5.2 思路5.3 代码 0.理…

C#实现List导出CSV:深入解析完整方案

C#实现List导出CSV&#xff1a;深入解析完整方案 在数据交互场景中&#xff0c;CSV文件凭借其跨平台兼容性和简洁性&#xff0c;成为数据交换的重要载体。本文将基于C#反射机制实现的通用CSV导出方案&#xff0c;结合实际开发中的痛点&#xff0c;从基础实现、深度优化到生产级…

字符串day7

344 反转字符串 字符串理论上也是一个数组&#xff0c;因此只需要用双指针即可 class Solution { public:void reverseString(vector<char>& s) {for(int i0,js.size()-1;i<j;i,j--){swap(s[i],s[j]);}} };541 反转字符串 自己实现一个反转从start到end的字符串…

Grafana XSSOpenRedirectSSRF漏洞复现(CVE-2025-4123)

免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 前…

私服 nexus 之间迁移 npm 仓库

本文介绍如何将一个 Nexus 特定仓库中的 npm 包内容迁移到另一个 Nexus 特定仓库。此过程适用于需要重构仓库结构或合并仓库的场景。 迁移脚本 以下是完整的迁移脚本&#xff0c;它会自动完成以下操作&#xff1a; 从源仓库获取所有 npm 包列表下载每个包的 .tgz 文件解压并…

Django ToDoWeb 服务

我们的任务是使用 Django 创建一个简单的 ToDo 应用程序,允许用户添加、查看和删除笔记。我们将通过设置 Django 项目、创建 Todo 模型、设计表单和视图来处理用户输入以及创建模板来显示任务来构建它。我们将逐步实现核心功能以有效地管理 todo 项。 Django ToDoWeb 服务 …

阿里云服务器遭遇DDoS攻击?低成本第三方高防解决方案全解析

阿里云服务器因高性能和稳定性备受青睐&#xff0c;但其DDoS高防服务的价格常让中小企业望而却步。面对动辄每月数万元的防护成本&#xff0c;许多用户不禁疑问&#xff1a;能否通过第三方高防服务保护阿里云服务器&#xff1f;如何实现低成本高效防御&#xff1f; 本文将结合技…

2025山东CCPC补题

2025山东CCPC补题 目录 2025山东CCPC补题K - UNO&#xff01; &#xff08;双端队列的简单应用&#xff09;M - 第九届河北省大学生程序设计竞赛 &#xff08;二进制枚举模拟&#xff09;J - Generate 01 String 感觉这场比赛的题目挺不错的&#xff1b;没有说那些为了算法而算…

体绘制学习

一、基本概念 体绘制是对一个三维物体数据进行采样与拟合的过程。 在体绘制中用vtkVolume渲染数据 渲染数据类数据转换类几何渲染vtkActorvtkPolyDataMapper体渲染vtkVolumevtkVolumeRayCastMapper 体绘制常用算法如下。 光线投射法。 优点是可视化结果质量好。缺点是计算…

告别“盘丝洞”车间:4-20mA无线传输如何重构工厂神经网?

4-20ma无线传输是利用无线模块将传统的温度、压力、液位等4-20mA电流信号转换为无线信号进行传输。这一技术突破了有线传输的限制&#xff0c;使得信号可以在更广泛的范围内进行灵活、快速的传递&#xff0c;无线传输距离可达到50KM。达泰4-20ma无线传输模块在实现工业现场应用…

VB.NET与SQL连接问题解决方案

1.基本连接步骤 使用SqlConnection、SqlCommand和SqlDataReader进行基础操作&#xff1a; vb.net Imports System.Data.SqlClient Public Sub ConnectToDatabase() Dim connectionString As String "ServermyServerAddress;DatabasemyDataBase;Integrated Security…

ElasticSearch--DSL查询语句

ElasticSearch DSL查询文档 分类 查询类型功能描述典型应用场景示例语法查询所有匹配所有文档&#xff0c;无过滤条件数据预览/测试json { "query": { "match_all": {} } }全文检索查询对文本字段分词后匹配&#xff0c;基于倒排索引搜索框模糊匹配、多字段…

DDR4读写压力测试

1.1测试环境 1.1.1整体环境介绍 板卡&#xff1a; pcie-403板卡 主控芯片&#xff1a; Xilinx xcvu13p-fhgb2104-2 调试软件&#xff1a; Vivado 2018.3 代码环境&#xff1a; Vscode utf-8 测试工程&#xff1a; pcie403_user_top 1.1.2硬件介绍 UD PCIe-403…

在 Windows 上使用 WSL 安装 Ansible详细步骤

在 Windows 上使用 WSL&#xff08;Windows Subsystem for Linux&#xff09; 安装 Ansible 是目前最推荐的方式&#xff0c;因为 Ansible 本身是为 Linux 环境设计的&#xff0c;不支持原生 Windows 作为控制节点。 下面是一个 详细步骤指南 &#xff0c;帮助你在 Windows 上…

编写第一个ros程序

1.下载VScode 下载链接如下&#xff1a; Download Visual Studio Code - Mac, Linux, Windows 下载ARM64下的.deb文件 打开虚拟机&#xff0c;再rosnoetic下新建一个文件夹VSCODE&#xff0c;将windows下的文件导入该文件夹下如下图。 在该文件夹下右键选择在终端中打开 输入…

代码随想录算法训练营第60期第四十九天打卡

大家好&#xff0c;今天我们还是继续我们的动态规划章节&#xff0c;可能有的朋友已经开始厌倦了说为什么动态规划怎么这么多题目&#xff0c;大家可以想想我们前面其实刷过好几种类型的动态规划的经典题目比如说各式各样的背包问题当然包括0-1背包&#xff0c;完全背包&#x…

centos7.9离线升级内核到4.19.12详细教程

cenots7.9默认安装的内核版本是:3.10.0-1160.119.1.el7.x86_64,在安装nvidia显卡驱动的时候,提示内核版本过低,需要升级内核版本,升级完成之后,就可以顺利的安装上nvidia显卡驱动了,实测有效。 一、查看当前内核版本命令 uname -r二、下载离线内核的rpm包