红黑树模拟

1.红黑树概念

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

2.红黑树性质

        1.每个节点不是红色就i是黑色

        2.根节点是黑色的

        3.如果一个节点是红色的,则它的两个孩子节点是黑色的

        4.对于每个节点,从该节点到其所有后代的简单途径上,均包含相同个数的黑色节点

        5.每个叶子节点都是黑色的(此处的叶子节点指的是空节点)

3.红黑树节点定义

// 节点颜色
enum Color
{
	RED, 
	BLACK
};

// 红黑树节点定义
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(pair<K, V> kv)
		:_kv(kv)
	{}


	RBTreeNode* _left = nullptr;    // 节点的左孩子
	RBTreeNode* _right = nullptr;   // 节点的右孩子
	RBTreeNode* _parent = nullptr;  // 节点的双亲(红黑树需要旋转)

	Color _col = RED;               // 节点的颜色
	pair<K, V> _kv;                 // 节点的值
};

将节点默认为红色,可以保证任条简单路径的黑色简单的个数相同 

4.红黑树的插入操作

红黑树实在二叉搜索树的基础上加上其平衡条件,因此红黑树的插入可以分为两步:

        1. 按照二叉搜索树的规则插上新节点

class RBTRee
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V> kv)
	{
		Node* newnode = new Node(kv);
		if (_root == nullptr)
		{
			_root = newnode;
		}
		else
		{
			Node* parent = nullptr;
			Node* cur = _root;
			//寻找插入位置
			while (cur)
			{
				if (kv.first > cur->_kv.first) cur = cur->_right;
				else if (kv.first < cur->_kv.first) cur = cur->_left;
				else return false;
			}

			if (kv.first > cur->_kv.first) parent->_right = newnode;
			else parent->_left = newnode;

			//调整节点颜色

		}

		// 节点的颜色可能被修改,将其改为黑色
   
		_root->_col = BLACK;

        return true;
	}

private:
	Node* _root = nullptr;
};

        2. 检测新节点插入后,红黑树的性质是否遭到破坏

                因为新节点默认是红色的,因此:如果其双亲节点的颜色为黑色,没有违反红黑树的性质,则不需要调整;但当新插入的节点的双亲节点为红色时,就违反了红黑树的性质,就需要分情况讨论。

cur:为当前节点,p为父节点,g为祖父节点,u为叔叔节点

a. cur为红,p为红,g为黑,u存在且为红

        注意:此处的树可能是一颗完整的树,也有可能是一颗子树

如果g是根节点,需要将g改为黑色

如果g是子树,g一定有父节点,且g的父节点如果为红色,则需要继续向上调整

 cur与p节点均为红色,将p,u改为黑,g改为红,继续向上调整

将grandparent节点改为红色,uncle和parent改为黑色,继续向上调整

Node* uncle = grandparent->_right;

// uncle存在且为红色
if (uncle && uncle->_col == RED)
{
	parent->_col = BLACK;
	uncle->_col = BLACK;
	grandparent->_col = RED;

	// 继续向上调整
	cur = grandparent;
	parent = cur->_parent;
}

b.cur为红,p为红,g为黑,u不存在或u存在且为黑(cur与parent同侧)

1. 如果u节点不存在,则cur一定是新插入的节点,因为cur如果不是新插入的节点,则cur与p一定有一个节点是黑色,就不满足每条路径黑色节点相同

2.如果u节点存在,则其一定是黑色的,那么cur位置原来的节点一定是黑色的,是由于cur子树在调整过程中将cur的颜色变成了红色

直接经行右旋操作,再调整颜色

if (parent == grandparent->_left)
{
	if (parent->_left == cur)
	{
		_RotateR(grandparent);
		parent->_col = BLACK;
		grandparent->_col = RED;
	}
}

c. cur为红,p为红,g为黑,u不存在或u存在且为黑(cur与parent异侧)

先对parent经行左旋将其变为b情况,再经行一次右旋。 

if (uncle || uncle->_col == BLACK)
{
	if (parent == grandparent->_left)
	{
		Node* uncle = grandparent->_right;
		if (parent->_right == cur)
		{
			_RotateL(parent);
			_RotateR(grandparent);

			cur->_col = BLACK;
			grandparent->_col = RED;
		}

		break;
	}
}

旋转操作 

void _RotateR(Node* parent)
{
	Node* grandparent = parent->_parent;
	Node* LSub = parent->_left;
	Node* LSubR = LSub->_right;

	parent->_left = LSubR;
	if (LSubR) LSubR->_parent = parent;

	LSub->_right = parent;
	parent->_parent = LSub;

	LSub->_parent = grandparent;
	if (parent == _root) _root = LSub;
	else
	{
		if (grandparent->_left == parent) grandparent->_left = LSub;
		else grandparent->_right = LSub;
	}
}
void _RotateL(Node* parent)
{
	Node* grandparent = parent->_parent;
	Node* RSub = parent->_right;
	Node* RSubL = RSub->_left;

	parent->_right = RSubL;
	if (RSubL) RSubL->_parent = parent;

	RSub->_left = parent;
	parent->_parent = RSub;

	RSub->_parent = grandparent;
	if (parent == _root) _root = RSub;
	else
	{
		if (grandparent->_left == parent) grandparent->_left = RSub;
		else grandparent->_right = RSub;
	}
}

5.红黑树的验证

红黑树的检测分为两步

1.检测其是否满足二叉搜索树的性质

中序遍历结果是否有序

void _InOrder(Node* root)
{
	if (root == nullptr) return;
	_InOrder(root->_left);
	cout << root->_kv.first << " " << root->_kv.second << endl;
	_InOrder(root->_right);
}

2.检测其是否满足红黑树的性质。

bool IsBalance()
{
	if (_root->_col == RED) return false;
	int SumOfBlack = 0;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_col == BLACK) SumOfBlack++;
		else
		{
			if (cur->_parent && cur->_parent->_col == RED) return false;
		}
		cur = cur->_left;
	}

	return _check(_root, SumOfBlack, 0);
}

bool _check(Node* root, int sum, int path)
{
	if (root == nullptr)
	{
		return sum == path;
	}
	return _check(root->_left, sum, path + 1) && _check(root->_right, sum, path + 1);
}

6.红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是O(log N),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的二倍,相对而言,降低了旋转的次数,所以经行增删的性能比AVL树更优,且红黑树的事项比较简单。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL InnoDB Cluster 高可用集群部署

MySQL InnoDB Cluster 简介 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.4/en/mysql-innodb-cluster-introduction.html 本章介绍 MySQL InnoDB Cluster&#xff0c;它结合了 MySQL 技术&#xff0c;使您能够部署和管理完整的 MySQL 集成高可用性解决方案。 说…

SOC模块LoRa-STM32WLE5有哪些值得关注

SoC 是片上系统的缩写&#xff0c;是一种集成芯片&#xff0c;集成了计算机或其他电子系统的所有或大部分组件。这些组件通常包括中央处理器 (CPU)、内存、输入/输出接口和辅助存储接口。包含数字、模拟、混合信号和通常的 RF 信号处理功能&#xff0c;具体取决于应用。片上系统…

优质快刊合集!内含TOP刊、CCF推荐期刊!编辑友好,极速发表!

【SciencePub学术】本期给大家推荐的是几本计算机快刊合集&#xff0c;内含优质TOP刊&#xff0c;现在版面已经所剩不多。且均属于我处目前进展很顺的期刊&#xff0c;大家可以放心投稿&#xff01; 计算机工程类 SCI&#xff08;TOP刊 / CCF-C类&#xff09; 【期刊简介】IF…

高斯过程的数学理解

目录 一、说明 二、初步&#xff1a;多元高斯分布 三、 线性回归模型与维度的诅咒 四、高斯过程的数学背景 五、高斯过程的应用&#xff1a;高斯过程回归 5.1 如何拟合和推理高斯过程模型 5.2 示例&#xff1a;一维数据的高斯过程模型 5.3 示例&#xff1a;多维数据的高斯过程模…

滑动窗口算法系列|基础概念|例题讲解

大家好,我是LvZi,今天带来滑动窗口算法系列|基础概念|例题讲解 一.滑动窗口问题基础概念 滑动窗口本质上是同向双指针问题,脱胎于双指针.使用两个指针l, r维护一定长度的数组区间,在r 指针遍历的过程中,执行进窗口,判断,更新结果,出窗口 等操作,当r指针遍历完毕,就能得到最后…

Study--Oracle-05-Oracler体系结构

一、oracle 体系概览 Oracle数据库的体系结构通常包括以下主要组件&#xff1a; 1、实例&#xff08;Instance&#xff09;&#xff1a;运行数据库的软件环境&#xff0c;包括内存结构&#xff08;SGA&#xff09;和进程结构&#xff08;Background Processes and User Proces…

如何一键修复0x0000011b错误,修复0x0000011b终极指南

在使用Windows操作系统和网络打印机的过程中&#xff0c;很多用户可能遇到了一个常见的错误代码“0x0000011b”。这个问题通常发生在尝试连接或使用网络打印机时&#xff0c;尤其是在安装了特定Windows安全更新后。本文将详细介绍如何快速一键修复此问题&#xff0c;确保您的打…

利用MMDetection将单阶段检测器作为Faster R-CNN的RPN

将单阶段检测器作为RPN 一、在 Faster R-CNN 中使用 FCOSHead 作为 RPNHead与原始配置的对比结果Neck (FPN)RPN HeadROI Head学习率 使用单阶段检测器作为RPN的优势1. 速度提升2. 准确性3. 简化架构4. 灵活性 二、评估候选区域三、用预先训练的 FCOS 训练定制的 Faster R-CNN 本…

开源模型应用落地-FastAPI-助力模型交互-WebSocket篇(五)

一、前言 使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。 FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,F…

shellhub 部署

1、环境介绍 操作系统&#xff1a;龙蜥os 7.9 2、安装docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i sdownload.docker.commirrors.aliyun.c…

江协科技51单片机学习- p23 DS1302实时时钟

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

【TB作品】智能台灯,ATMEGA16单片机,Proteus仿真

智能台灯 1 adc检测光强光敏电阻 显示电压 2 光强太高 也就是高于临界值 就关闭小灯 3 光强太低 也就是低于临界值 就打开小灯 3 按键修改临界值 显示 实验报告&#xff1a;基于ATMEGA16单片机的智能台灯设计与Proteus仿真 1. 实验背景 智能台灯是一种能够根据环境光强自动调…

计算机网络-第5章运输层

5.1运输层协议概述 5.1.1进程之间的通信 运输层向它上面的应用层提供通信服务&#xff0c;它属于面向通信部分的最高层&#xff0c;同时也是用户功能中的最低层。 通信的两端应当是两个主机中的应用进程。 运输层复用和分用&#xff1a;复用指在发送方不同的应用进程都可以…

Vue2组件传值(通信)的方式

目录 1.父传后代 ( 后代拿到了父的数据 )1. 父组件引入子组件&#xff0c;绑定数据2. 子组件直接使用父组件的数据3. 依赖注入(使用 provide/inject API)1.在祖先组件中使用 provide2.在后代组件中使用 inject 2.后代传父 &#xff08;父拿到了后代的数据&#xff09;1. 子组件…

【Qt】认识Qt界面Hello world小程序

一.认识Qt界面 1.左边栏 在编辑模式下&#xff0c;左边竖排的两个窗⼝叫做 "边栏" 。 ① 是项⽬⽂件管理窗⼝ ② 是打开⽂件列表窗⼝。 边栏⾥的窗⼝数⽬可以增加&#xff0c;边栏⼦窗⼝标题栏有⼀排⼩按钮&#xff0c;最右边的是关闭按钮&#xff0c;倒数第⼆个是 …

千元好礼等你来拿 MatrixOne最强体验官

开发者集合&#xff01;[MatrixOne最强体验官]带着丰厚的奖品走来啦&#xff01;MatrixOne 是一款高度兼容 MySQL 语法的 HTAP 数据库&#xff0c;MatrixOne Cloud (MO Cloud) 是基于 MatrixOne 内核的全托管云原生数据平台&#xff0c;具备实时 HTAP&#xff0c;多租户&#x…

Unity Shader 软粒子

Unity Shader 软粒子 前言项目Shader连连看项目渲染管线设置 鸣谢 前言 当场景有点单调的时候&#xff0c;就需要一些粒子点缀&#xff0c;此时软粒子就可以发挥作用了。 使用软粒子与未使用软粒子对比图 项目 Shader连连看 这里插播一点&#xff0c;可以用Vertex Color与…

antd(5.x) Popover 的content有个modal,关不掉了

问题描述&#xff1a; 如上图所示&#xff0c;我的提示modal 关不掉了&#xff0c;思考问题症结在handleVisibleChange const content (<div className{styles.box}>别的样式</div>{/* 链接 */}<div className{styles.linkBox}><Modaltitle{提示}open{…

deepin基于apt-mirror同步软件源及构建本地内网源

1.安装apt-mirror sudo apt install -y apt-mirror2.配置apt-mirror(/etc/apt/mirror.list) sudo cp /etc/apt/mirror.list /etc/apt/mirror.list.deepin.bak #备份配置文件 sudo gedit /etc/apt/mirror.list修改如下&#xff1a; deb [trustedyes] https://mirrors.bfsu.ed…

在线如何快速把图片变小?图片轻松修改大小的3个在线工具

随着现在图片在工作和生活中的广泛使用&#xff0c;在使用图片的时候经常会因为图片太大的问题受到影响&#xff0c;比较简单的一种处理方法可以通过压缩图片的方式来缩小图片大小&#xff0c;那么图片压缩具体该怎么来操作呢&#xff1f;下面就给大家分享几款图片在线压缩工具…