红黑树模拟

news2024/11/17 13:38:17

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.coloradmin.cn/o/1882563.html

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

相关文章

基于Cisco模拟器的组网实验

课程目的 综合运用所学的网络原理、网络规划和网络集成等知识理论&#xff0c;按照下图所示&#xff0c;完成网络的规划、集成与配置&#xff0c;并利用ACL实现对网络的管理。 实验内容 连接并配置路由器&#xff0c;配置路由协议&#xff08;RIP或OSPF&#xff09;&#xf…

[Microsoft Office]Word设置页码从第二页开始为1

目录 第一步&#xff1a;设置页码格式 第二步&#xff1a;设置“起始页码”为0 第三步&#xff1a;双击页码&#xff0c;出现“页脚”提示 第四步&#xff1a;选中“首页不同” 第一步&#xff1a;设置页码格式 第二步&#xff1a;设置“起始页码”为0 第三步&#xff1a;双…

现在电气真的比不过计算机吗 ?

电气工程和计算机科学在今天的科技和工业领域中各有其重要性和发展空间&#xff0c;并不存在简单的比较谁“比不过”谁的情况。我收集制作一份plc学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向&#xff0c;包括了编程教学&#xff…

【爱上C++】详解string类2:模拟实现、深浅拷贝

在上一篇文章中我们介绍了string类的基本使用&#xff0c;本篇文章我们将讲解string类一些常用的模拟实现&#xff0c;其中有很多细小的知识点值得我们深入学习。Let’s go&#xff01; 文章目录 类声明默认成员函数构造函数析构函数拷贝构造函数深浅拷贝问题传统写法现代写法…

哪个量化软件最好用?散户也可以很快上手!QMT!

一、QMT是什么 QMT&#xff08;Quantitative Multi-market Trading System&#xff09;是一款专为高净值客户、量化爱好者及专业量化投资者设计的量化交易软件。它集行情显示、策略研究、交易执行和风控管理于一体&#xff0c;为投资者提供全方位的量化交易解决方案 二、QMT量化…

SAP配置发布WebService接口并调用(超级详细)

文章目录 前言一、案例介绍/笔者需求二、WebService是什么&#xff1f; a.传输协议 b.数据协议 c.WSDL d.UDDI 三、WebService 和 WebApi 的区别以及优缺点 a.主要区别 b.优缺点 四、SAP如何发布一个webser…

Perforce网络研讨会预告 | HelixCore vs SVN vs ClearCase:嵌入式开发中的数据管理趋势及工具对比分析

现如今&#xff0c;开发嵌入式软件涉及的规模比以往任何时候都庞大。团队在全球范围内不断扩展&#xff0c;文件数量呈指数级增长&#xff0c;项目每年所涉及的数字资产和元数据也更多&#xff0c;并且越来越多的团队成员要在相同的复杂项目中并行工作。 面对如此庞大的开发规…

《梦醒蝶飞:释放Excel函数与公式的力量》7.4 MID函数

第七章&#xff1a;文本处理函数 第4节&#xff1a;7.4 MID函数 7.4.1.MID函数简介 MID函数用于从文本字符串的指定位置开始提取指定数量的字符。它特别适用于从字符串中提取子字符串或处理具有特定格式的数据。 语法&#xff1a; MID(text, start_num, num_chars) - **t…

聚焦政企人才培养,打造多元化课程体系

树莓集团在课程内容上展现了显著的多元化特点&#xff0c;通过广泛的合作、创新的课程内容和产教融合的教学模式&#xff0c;为广大学子提供了全面、系统、专业的教育资源和实践机会。 1、专业广度&#xff1a;树莓集团旗下拥有树莓教育成都王老师摄影培训学校&#xff0c;作为…

Elasticsearch:Painless scripting 语言(一)

Painless 是一种高性能、安全的脚本语言&#xff0c;专为 Elasticsearch 设计。你可以使用 Painless 在 Elasticsearch 支持脚本的任何地方安全地编写内联和存储脚本。 Painless 提供众多功能&#xff0c;这些功能围绕以下核心原则&#xff1a; 安全性&#xff1a;确保集群的…

ZXL-2000砌体砂浆强度点荷仪

一、产品简介&#xff1a; 砌体砂浆强度点荷仪&#xff08;又名&#xff1a;砂浆点荷仪&#xff09;&#xff0c;是根据GB/T50315-2000《砌体工程现场检验技术规程》而研制生产的。是砌体砂浆强度检测的专用仪器&#xff0c;其特点是能在现场或试验室直接测试&#xff0c;不影…

bmob Harmony快速开发手机号一键登录功能

最近用Bmob的鸿蒙SDK尝试了Harmony开发&#xff0c;做了一个几乎每个应用都会有的功能&#xff1a;手机号码短信验证码一键注册登录的功能&#xff0c;感觉简直爽的不要不要的&#xff0c;ArkUI可见即可得的UI交互设计体验&#xff0c;配合Bmob后端云一如既往简单易用的风格&am…

数据恢复篇:如何在 Android 手机上恢复未保存/删除的 Word 文档

在 Android 手机上访问 Word 文档通常很简单&#xff0c;但是当这些重要文件被删除或未保存时会发生什么&#xff1f;这种情况虽然令人痛苦&#xff0c;但并非毫无希望。到 2024 年&#xff0c;有几种强大的方法来处理此类数据丢失。本指南重点介绍如何在Android手机上恢复已删…

【java开发环境】多版本jdk 自由切换window和linux

win10 一、准备 各种版本的jdk&#xff0c;按自己的需要下载。 我这里是需要jdk17和jdk8。 1、jdk17 下载&#xff1a;Java Downloads | Oracle&#xff0c;选择exe后缀文件 2、jdk8下 载&#xff1a;Java Downloads | Oracle&#xff0c;选择exe后缀文件 二、详细步骤 1、…

leetcode 403周赛 包含所有1的最小矩形面积||「暴力」

3197. 包含所有 1 的最小矩形面积 II 题目描述&#xff1a; 给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形&#xff0c;并且满足 grid 中所有的 1 都在这些矩形的内部。 返回这些矩形面积之和的 最小 可能值。 注意…

狗都能看懂的Reinforcement Learning简介

文章目录 一、什么是强化学习二、强化学习的应用 一、什么是强化学习 强化学习的流程可以用上面这张图来说明&#xff1a;智能体&#xff08;Agent&#xff09;对环境进行观测&#xff0c;然后根据观测结果&#xff08;Observation / State&#xff09;采取相应的动作&#xff…

C++中的类型转换操作符:static_cast reinterpret_cast const_cast dynamic_cast

目录​​​​​​​ C语言中的类型转换 C中的类型转换 C中的类型转换操作符 static_cast reinterpret_cast const_cast volatile关键字 赋值兼容 dynamic_cast C语言中的类型转换 基本概念&#xff1a;赋值运算符左右两侧类型不同&#xff0c;或形参与实参类型不匹配…

LayerSkip:加速大模型推理的端到端解决方案

大模型&#xff08;LLMs&#xff09;在多种应用中表现出色&#xff0c;但其高昂的计算和内存需求导致部署成本昂贵&#xff0c;尤其是在GPU服务器上。现有加速方案在部署到普通GPU时往往会导致准确性显著下降&#xff0c;而将大模型&#xff08;LLMs&#xff09;进一步加速以部…

Pycharm的终端(Terminal)中切换到当前项目所在的虚拟环境

1.在Pycharm最下端点击终端/Terminal, 2.点击终端窗口最上端最右边的∨&#xff0c; 3.点击Command Prompt&#xff0c;切换环境&#xff0c; 可以看到现在环境已经由默认的PS(Window PowerShell)切换为项目所使用的虚拟环境。 4.更近一步&#xff0c;如果想让Pycharm默认显示…

单电源RS-232收发器UM3221E/UM3222E/UM3232E

一般描述 UM3232 TSSOP16封装外观和丝印 UM3221E/UM3222E/UM3232E 系列是 3.3V 供电的 RS-232 收发器&#xff0c;适用于便携式或手持式应用。UM3221E 有一个驱动器/一个接收器&#xff0c;而 UM3222E/UM3232E 有两个驱动器/两个接收器。该器件具有低功耗、高数据速率能力和增强…