波奇学C++:红黑树

news2024/11/16 9:34:06

红黑树性质:

1.每个结点不是红色就是黑色。

2.根节点是黑色

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

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

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

6.红黑路径的计算从根结点到NIL结点(红黑树特殊的黑色结点)

7.红黑树路径节点个数计算,不包括叶节点

8.最长路径的节点个数不会超过最短路径节点个数的两倍

证明满足上述条件,最长路径的节点个数不会超过最短路径节点个数的两倍。

最长路径*1/2<=黑节点个数,最短路径的黑结点个数=最长路径黑结点个数,

最小路径>=黑节点个数>=最长路径*1/2。

 cur,parent,uncle为红,

grandparent再进行判断

cur,parent为红,uncle为黑或者uncle不存在

parent为黑,grandparent为红,三角型表示存在至少一个黑色节点来维持左右黑色节点数目平衡。

双旋,parent先左旋转,cur再右旋。

uncle不存在时同理

总结:同理左右单旋取决于cur在parent的哪一边 ,unle颜色决定是否旋转。

补充:uncle为黑时,cur必然不是新插入节点,原因为了维持左右黑节点数目平衡,cur下面必然还有其他节点。

分析:红黑树最重要的两个性质,红红不能相连,左右黑数目相同。当红红相连时,必然有其一变变黑,新增的黑色节点只能在根或者子树的根处来保持平衡,旋转的目的就是如此平衡左右黑节点。

代码如下:


enum Colour
{
	RED,
	BLACK
};
template<class K,class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;
	Colour _col;
	RBTreeNode(const pair<K,V>& kv)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_kv(kv)
		,_col(BLACK)
	{}
};
template<class K,class V>
struct 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* parent = nullptr;
		Node* cur = _root;
		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)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else //u不存在或者存在且为黑
				{
					if (cur==parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
			}
			else
			{
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else //u不存在或者存在且为黑
				{
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateR(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 = parent->_left;
		parent->_left = curleft;
		if (curleft)
		{
			curleft->_parent = parent;
		}
		cur->_left = parent;
		Node* ppnode = parent->_parent;
		parent->_parent = cur;
		if (parent == _root)
		{
			_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;
		cur->_right = parent;

		Node* ppnode = parent->_parent;
		if (curright)
		{
			curright->_parent = parent;
		}
		parent->_parent = cur;
		if (ppnode == _root)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
		}
		
		
	}
	bool CheckColour(Node* root,int blacknum,int benchmark)
	{
		if (root == nullptr)
		{ 
			if (blacknum > 2 * 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 CheckColour(root->_left,blacknum,benchmark)
			&& CheckColour(root->_right,blacknum,benchmark);
	}
	bool IaBalance()
	{
		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 CheckColour(root,0,benchmark);
	}

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

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

相关文章

主机ping不通虚拟机,虚拟机可以ping同主机

问题&#xff1a;主机ping不通虚拟机 虚拟机可以ping通主机(192.168.43.140)和外网&#xff08;www.baidu.com) 解决方法&#xff1a; 1.打开【控制面板】-->【网络和Internet】-->【网络连接】 2.选择VMnet8 右键【属性】 3.修改 IP地址&#xff08;I&#xff09;和 子…

1、内核加载模块

一、静态加载 1、新功能源码与内核源码一起编译进uImage文件内 新功能源码与Linux内核源码在同一目录结构下在linux-3.14/drivers/char/目录下编写hello.c文件&#xff0c;内容如下 #include <linux/module.h> #include <linux/kernel.h>int __init myhello_ini…

oracle OCP OCM MySQL OCP认证难吗?

好多人在初次考OCP时&#xff0c;不知道如何选择&#xff0c;本文让姚远ACE老师为大家总结一下吧&#xff01; 选择OCP认证时要注意的问题&#xff1a; 1&#xff0c;授课老师师资经验&#xff08;非常重要&#xff09; 2&#xff0c;课程大纲 3&#xff0c;试听课程 4&am…

零食食品经营小程序商城的作用是什么

零食几乎可以涵盖每个年龄阶段&#xff0c;同时又是市场中常见的零售批发商品&#xff0c;在多个场景中都有销售/购买属性&#xff0c;对消费者来说&#xff0c;购买零食的渠道多种多样&#xff0c;无论线下还是线上&#xff0c;都可随心而购。 庞大市场升级促进下&#xff0c…

医学影像归档与通讯系统(PACS)系统源码 PACS三维图像后处理技术

医学影像归档与通讯系统&#xff08;PACS&#xff09;系统源码 PACS三维图像处理 医学影像归档与通讯系统&#xff08;PACS&#xff09;系统&#xff0c;是一套适用于从单一影像设备到放射科室、到全院级别等各种应用规模的医学影像归档与通讯系统。PACS集患者登记、图像采集、…

国庆特别篇:中秋与国庆同日相迎

国庆特别篇&#xff1a;中秋与国庆同日相迎 国庆特别篇&#xff1a;中秋与国庆同日相迎 &#x1f389;摘要引言旅途风景分享 &#x1f5fa;️中秋团圆&#xff0c;返乡之路风景宜人的旅游胜地 技术探讨&#xff1a;Java中的可变参数 &#x1f680;什么是可变参数&#xff1f;使…

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型 1. 准备工作1.1 安装RabbitMQ1.2 简单部署搭建设计1.3 参考官网 2. RabbitMQ 形成集群的方法3. 搭建RabbitMQ集群3.1 部署架构3.2 rabbitmq集群基础知识3.2.1 关于节点名称&#xff08;标识符&#xff09;3.2.…

《操作系统真象还原》 第 01 章 部署工作环境 学习笔记

0. 内容说明 本内容依据《操作系统真象还原》进行学习&#xff0c;在学习过程中&#xff0c;由于新版本和旧版本bochs存在参数差异&#xff0c;故此会出现一些调试错误。也记录对应的解决方案。 1. 需要的编译器 对于现代OS来说&#xff0c;主要使用 C语言 和 汇编语言 两种…

剑指offer——JZ26 树的子结构 解题思路与具体代码【C++】

一、题目描述与要求 树的子结构_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入两棵二叉树A&#xff0c;B&#xff0c;判断B是不是A的子结构。&#xff08;我们约定空树不是任意一个树的子结构&#xff09; 假如给定A为{8,8,7,9,2,#,#,#,#,4,7}&#xff0c;B为{8,9,2}&…

【智能家居项目】裸机版本——字体子系统 | 显示子系统

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《智能家居项目》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 今天实现上图整个项目系统中的字体子系统和显示子系统。 目录 &#x1f004;设计思路&#x1…

无法启动此程序,因为计算机中“找不到msvcp140.dll”的解决方法

msvcp140.dll是Microsoft Visual C 2015 Redistributable的一个动态链接库文件&#xff0c;它是许多基于Visual Studio开发的应用程序和游戏的必要组件。当计算机上缺失msvcp140.dll文件时&#xff0c;可能会导致以下问题&#xff1a; 1. 程序无法启动&#xff0c;提示“找不到…

【多线程安全】死锁 锁竞争总结

下面有两段代码&#xff1a; public class test {private static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() -> {for (int i 0; i < 10000; i) {count;}});Thread t2 new Thread(() -> {for (i…

速通Redis基础(一):掌握Redis的字符串类型和命令

目录 字符串&#xff08;String&#xff09; 常见命令 SET GET MSET&MGET SETNX INCR INCRBY DECR DECRBY INCRBYFLOAT APPEND GETRANGE SETRANGE STRLEN Redis字符串类型命令总结 Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的…

机器学习基础之《分类算法(8)—随机森林》

一、什么是集成学习方法 1、定义 集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学习和作出预测。这些预测最后结合成组合预测&#xff0c;因此优于任何一个单分类的做出预测 谚语&#xff1a;三个臭皮匠顶个诸…

论文悦读(6)——PM操作系统之TreeSLS单级存储

TreeSLS &#xff08;SOSP23&#xff09; 1. 背景 (Background)1.1 内存-存储二级架构 (1, 2.1)1.2 单级架构 (2.2)1.3 总结 2. 动机 (Motivation)2.1 现有SLS性能低下 (2.3)2.2 现有SLS难以支持External Synchrony (1, 2.4)2.3 高速PM出现为SLS带来新的机遇与挑战 (1, 2.5) 3.…

CDN是什么?(网络零基础入门篇)

1.CDN的全称 是 Content Delivery Network&#xff0c;即内容分发网络。 其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节&#xff0c;使内容传输得更快、更稳定。 通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网…

探索古彝文的秘密,AI实现古籍传承

陈老老老板&#x1f934; &#x1f9d9;‍♂️本文专栏&#xff1a;生活&#xff08;主要讲一下自己生活相关的内容&#xff09;生活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f9d9;‍♂️本文简述&#xff1a;最新资讯&#xff0c;合合信息扫描全能王实现古彝文识别&…

sigmoid和softmax函数有什么区别

Sigmoid函数和Softmax函数都是常用的激活函数&#xff0c;但它们的主要区别在于应用场景和输出结果的性质。 Sigmoid函数&#xff08;也称为 Logistic函数&#xff09;&#xff1a; Sigmoid函数将输入值映射到0到1之间的连续实数范围&#xff0c;通常用于二元分类问题。 Si…

U-Net神经网络简明教程

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 在我们进入技术细节之前&#xff0c;考虑一下&#xff0c;为什么要使用 U-Net&#xff1f; 你可能在搜索语义分割时遇到过这一点&#xff0c;我很快就会写一篇博客&#xff0c;然后再看看这个。 制作此架构的初衷是用于生物…

Spring MVC程序开发(JavaEE进阶系列3)

目录 前言&#xff1a; 1.什么是Spring MVC 1.1MVC的定义 1.2MVC和Spring MVC的关系 1.3为什么要学习Spring MVC 2.Spring MVC项目的创建 3.Spring MVC框架的使用 3.1连接的功能 3.1.1RequestMapping 3.1.2GetMapping 3.1.3PostMapping 3.2获取参数的功能 3.2.1获…