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

【C++】红黑树插入操作实现以及验证红黑树是否正确

文章目录

  • 前言
  • 一、红黑树的插入操作
    • 1.红黑树结点的定义
    • 2.红黑树的插入
      • 1.uncle存在且为红
      • 2.uncle不存在
      • 3.uncle存在且为黑
    • 3.完整代码
  • 二、是否为红黑树的验证
    • 1.IsBlance函数
    • 2.CheckColor函数
  • 三、红黑树与AVL树的比较


前言

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的

红黑树的性质:

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 (每条路径上的黑色结点数量相同)
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
    在这里插入图片描述
    最短路径:全部都是黑节点的路径。
    最长路径:一黑一红相间的路径

一、红黑树的插入操作

1.红黑树结点的定义

enum Color {RED,BLACK
};
template<class K,class V>
struct RBTreeNode {RBTreeNode* _left;RBTreeNode* _right;RBTreeNode* _parent;pair<K, V>_kv;Color _col;//颜色RBTreeNode(const pair<K,V>&kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_col(RED)//结点默认给成红色是为了方便后续的插入//因为默认为黑色的话还需要考虑所有路径上黑色结点数量是否相同//太麻烦了{}
};

2.红黑树的插入

插入分为一下三种情况,因为我们插入的结点默认为红色,而红黑树定义中指出不能出现连续的两个红色结点,为了维持红黑树,我们需要对一些结点的颜色进行改变有时还需要旋转改变树的形状,至于有关旋转的函数Rotate,我已经在之前AVL树的模拟实现中详细说明了,这里就不多在赘述了【C++】AVL树的插入操作实现以及验证是否正确(带平衡因子),有需要的可以去看一下。

1.uncle存在且为红

这种情况就不需要考虑旋转了
在这里插入图片描述
在这里插入图片描述

2.uncle不存在

在这里插入图片描述

3.uncle存在且为黑

在这里插入图片描述
在这里插入图片描述

总结:
红黑树插入关键看uncle
1.uncle存在且为红,变色(uncle与parent变黑色,grandfather变红色),之后继续向上处理
2.uncle不存在或者uncle存在且为黑,旋转加变色,之后break
3.小规律:grandfather在这个过程中要不本来就为红色,要不就变成红色

3.完整代码

template<class K,class V>
class RBTree {typedef RBTreeNode<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 = nullptr;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;}else {return false;}}cur = new Node(kv);cur->_col = RED;//插入对应位置,默认为红色if (parent->_kv.first < kv.first) {parent->_right = cur;}else {parent->_left = cur;}cur->_parent = parent;//让新插入结点指向父亲while (parent && parent->_col == RED) {Node* grandfather = parent->_parent;if (parent = grandfather->_left) {Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED) {//uncle存在且为红parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上更新cur = grandfather;parent = cur->_parent;}else {//uncle不存在或者uncle为黑if (cur == parent->_left) {//     g//   p// cRotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else {//     g//   p//		cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else {// parent == grandfather->_rightNode* uncle = grandfather->_right;if (uncle && uncle->_col == RED) {//uncle存在且为红parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上更新cur = grandfather;parent = cur->_parent;}else {//uncle不存在或者uncle为黑if (cur == parent->_right) {// g//	  p//       cRotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else {// g//	  p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;//根节点必须为黑色return true;}void RotateL(Node* parent) {//左旋Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft) {curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;if (ppnode == nullptr) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left = parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateR(Node* parent) {//右旋Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright) {curright->_parent = parent;}cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}}
};

二、是否为红黑树的验证

1.IsBlance函数

bool IsBalance() {return IsBalance(_root);}bool IsBalance(Node* root) {if (root == nullptr) {return true;}if (root->_col != BLACK) {return false;}//根节点一定为黑色int benchmark = 0;Node* cur = _root;while (cur) {//算出最左边黑色结点的数目,为了与//其他路径黑色结点的数目作比较if (cur->_col == BLACK) {benchmark++;}cur = cur->_left;}return CheckColor(root, 0, benchmark);}

2.CheckColor函数

bool CheckColor(Node* root, int blacknum, int benchmark) {if (root == nullptr) {//root为空说明已经数完了一条路径的黑色结点//与原先数的最左的黑色节点数进行比较if (blacknum != benchmark) {return false;}return true;}if (root->_col == BLACK) {blacknum++;//当前路径黑色结点树++}if (root->_col == RED && root->_parent && root->_parent->_col == RED) {cout << root->_kv.first << "出现连续红色节点" << endl;//判断是否出现连续的红色结点return false;}//递归式对左右子树分别检验return CheckColor(root->_left, blacknum, benchmark) && CheckColor(root->_right, blacknum, benchmark);}

三、红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O( l o g 2 N log_2 N log2N),红黑树不追
求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,
所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红
黑树更多。

相关文章:

【C++】红黑树插入操作实现以及验证红黑树是否正确

文章目录 前言一、红黑树的插入操作1.红黑树结点的定义2.红黑树的插入1.uncle存在且为红2.uncle不存在3.uncle存在且为黑 3.完整代码 二、是否为红黑树的验证1.IsBlance函数2.CheckColor函数 三、红黑树与AVL树的比较 前言 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在…...

学信息系统项目管理师第4版系列07_项目管理知识体系

1. 项目管理原则 1.1. 勤勉、尊重和关心他人 1.1.1. 关键点 1.1.1.1. 关注组织内部和外部的职责 1.1.1.2. 坚持诚信、关心、可信、合规原则 1.1.1.3. 秉持整体观 1.1.2. 职责 1.1.2.1. 诚信 1.1.2.2. 关心 1.1.2.3. 可信 1.1.2.4. 合规 1.2. 营造协作的项目管理团队…...

Leetcode 2851. String Transformation

Leetcode 2851. String Transformation 0. 吐槽1. 算法思路 1. 整体思路2. 字符串匹配优化 2. 代码实现 题目链接&#xff1a;2851. String Transformation 0. 吐槽 这道题多少有点坑爹&#xff0c;题目本身挺有意思的&#xff0c;是一道数组题目&#xff0c;其实用数学方法…...

在PHP8中对数组进行计算-PHP8知识详解

在php8中&#xff0c;提供了丰富的计算函数&#xff0c;可以对数组进行计算操作。常见的计算函数如下几个&#xff1a;array_sum()函数、array_merge()函数、array_diff()函数、array_diff_assoc()函数、array_intersect()函数、array_intersect_assoc()函数。 1、array_sum()函…...

Android BottomSheetDialog最大展开高度问题

修改界面的时候遇到了这个问题,这个问题比较简单,网上解决方案也很多,这是 peekHeight 半展开高度,毕竟只是 dialog,全铺满就我们不必考虑 dialog 了 方法是在DialogFragment初始化dialog时处理 companion object {/*** 设置弹窗高度 默认展开无折叠情况 */ const val …...

记录Linux部署人脸修复GFPGAN项目Docker Python 使用

记录Linux 服务器使用人脸修复GFPGAN 项目 1:阿里云安装docker,用docker 是隔离环境,Python环境还真是麻烦… https://help.aliyun.com/zh/ecs/use-cases/deploy-and-use-docker-on-alibaba-cloud-linux-2-instances 2:关于docker 镜像,想找个好的镜像也是很难,百度吧,很多Li…...

如何编写可重入的函数?

编写可重入&#xff08;reentrant&#xff09;的函数是在多线程环境或并发编程中非常重要的任务。可重入函数是一种可以安全地被多个线程同时调用的函数&#xff0c;而不会导致数据竞争或不一致性的函数。在C语言中&#xff0c;编写可重入函数需要遵循一些特定的规则和技巧。本…...

使用纯C语言定义通用型数据结构的方法和示例

文章目录 前言以实现优先队列来描述实现思想基本类型的包装类型比较函数演示总结 前言 最近一段时间在复习数据结构和算法&#xff0c;用的C语言&#xff0c;不得不说&#xff0c;不学个高级语言再回头看C语言根本不知道C语言的强大和完美&#xff0c;不过相比之下也有许多不便…...

数据结构基础8:二叉树oj+层序遍历。

二叉树oj层序遍历 题目一&#xff1a;二叉树的销毁&#xff1a;方法一&#xff1a;前序遍历&#xff1a;方法二&#xff1a;后序遍历&#xff1a; 题目二&#xff1a;二叉树查找值为x的节点方法一&#xff1a;方法二&#xff1a;方法三&#xff1a; 题目三&#xff1a;层序遍历…...

Spring注解家族介绍:@RestController

前言&#xff1a; Spring Boot可以说是当前JAVA最为重要的一个框架&#xff0c;而Spring Boot的基石Spring中有着丰富的注解&#xff0c;因此我们会利用几篇文章来讲解我目前学到的各种注解&#xff0c;因此本类型文章的篇幅会比较短&#xff0c;主要着重于介绍各个注解。 目录…...

rocketmq

&#x1f353;代码仓库 https://gitee.com/xuhx615/rocket-mqdemo.git &#x1f353;基本概念 ⭐生产者(Producer)&#xff1a;消息发布者⭐主题&#xff08;Topic&#xff09;&#xff1a;topic用于标识同一类业务类型的消息⭐消息队列&#xff08;MessageQueue&#xff09…...

JAVA成员变量首字母小写,第二个字母大写报错问题(原因:Lombok与Spring冲突)

1、问题现象&#xff1a; JAVA类里定义成员变量使用首字母小写&#xff0c;第二个字母大写 Getter Setter public class BrandQueryObject extends QueryObject{private String pName; }结果页面报错&#xff0c;无法找到类型为 cn.wolfcode.ssm.query.BrandQueryObject 的对象…...

Python入门教程 |Python 错误和异常

Python3 错误和异常 作为 Python 初学者&#xff0c;在刚学习 Python 编程时&#xff0c;经常会看到一些报错信息&#xff0c;在前面我们没有提及&#xff0c;这章节我们会专门介绍。 Python 有两种错误很容易辨认&#xff1a;语法错误和异常。 Python assert&#xff08;断…...

API商品接口对接使用:从理论到实践

随着电子商务的飞速发展&#xff0c;API商品接口已成为现代电子商务应用程序不可或缺的一部分。通过API商品接口&#xff0c;开发者可以轻松地从其他应用程序或服务中获取商品信息&#xff0c;实现快速、高效的电子商务功能。本文将探讨API商品接口的概念、对接使用的方法以及一…...

解决stable diffusion webui1.6 wd1.4 tagger加载失败的问题

由于webui源码的变化&#xff0c;需要修改两个地方的import 1.tagger/ui.py # 第十行 # from webui import wrap_gradio_gpu_call # 原代码 from modules.call_queue import wrap_gradio_gpu_call1.preload.py # 第4行开始 # from modules.shared import models_path # 原…...

Python学习-实现简单的http服务

基于Python实现一个简单的HttpServer,当用户在浏览器中输入IP地址:8000时&#xff0c;则会返回index.html页面内容&#xff0c;访问其它信息&#xff0c;则会返回错误信息(404) """ httpserver v1.0 1.获取来自浏览器的请求&#xff0c; 2.判断如果请求内容是 …...

#循循渐进学51单片机#变量进阶与点阵LED#not.6

1、掌握变量的作用域及存储类别。 局部变量 函数内部声明的变量&#xff0c;只在函数内部有效&#xff0c;在本函数以外是不能使用的&#xff0c;叫局部变量。 全局变量 在函数外部声明的变量就是全局变量&#xff0c;一个源程序可以包含一个或多个函数&#xff0c;全局变量…...

访问者模式

图片转载自 #include<iostream> using namespace std; #include<list> /*模板工厂单例化&#xff0c;所有的商品被注册进工厂中*/ /*访问者模式&#xff08;行为型模式&#xff09; 访问者&#xff0c;被访问者 visit accept 让访问变成一种操作&#xff0c;不同…...

epoll 的实现

epoll 这么好&#xff0c;为什么迟至 2.6 版本的 kernel 才支持(epoll manual: The epoll API was introduced in Linux kernel 2.5.44.)&#xff1f;2.4 版本的 kernel 不支持 epoll&#xff1f; 原因很简单&#xff0c;epoll 没什么神奇的。在早期没有太多的并发连接要处理&…...

怎么用excel管理固定资产

在当今的数字时代&#xff0c;我们已经习惯了使用各种电子工具来提高我们的生产力。其中&#xff0c;Excel无疑是一个强大的工具&#xff0c;它不仅可以帮助我们处理数据&#xff0c;还可以用来进行复杂的计算和分析。然而&#xff0c;你可能不知道的是&#xff0c;Excel也可以…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...