【数据结构】:红黑树

1、红黑树的简介

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构。

红黑树是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。 

红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。 

它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目

2、红黑树的优点

  • 红黑树保证了一种弱平衡,即树的高度最多是2倍的对数级别。这使得红黑树在插入和删除操作时具有更高的灵活性
  • AVL树是一种严格的平衡树,保证任何节点的左子树和右子树的高度差(平衡因子)不超过1。这确保了AVL树在平衡方面表现更好,但在插入和删除操作时可能需要更多的旋转来维持平衡
  • 红黑树是具备了某些特性的二叉搜索树,能解决非平衡树问题,红黑树是一种接近平衡的二叉树(说它是接近平衡因为它并没有像AVL树的平衡因子的概念,它只是靠着满足红黑节点的5条性质来维持一种接近平衡的结构,进而提升整体的性能,并没有严格的卡定某个平衡因子来维持绝对平衡)

3、红黑树的基本概念和性质

3.1、红黑树的基本定义 

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的 
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点 
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

 3.2、红黑树性质的要点

  • 根节点是黑色的
  • 不能有两个相连的红色节点。这意味着从任意节点到其子节点的路径上不能出现连续的红色节点,以避免出现不平衡情况
  • 从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同。这确保了树的高度始终保持在一个合理的范围内,从而保证了高效的查找操作
  • 空节点(NIL节点)被认为是黑色的。这样可以确保每个路径上的黑色节点数量相等,即使是经过了空节点的路径。
  • 性质3和性质4我们可以推出一个红黑树中最长路径应该是最短路径的二倍,最短路径:全为黑,最长路径:一黑一红
     

我们需要注意的是空节点(NIL节点)被认为是黑色的,从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同

 4、红黑树的效率

4.1 红黑树效率


红黑树的查找,插入和删除操作,时间复杂度都是O(logN)

4.2 红黑树和AVL树的比较

  • AVL树的时间复杂度虽然优于红黑树,但是对于现在的计算机,cpu太快,可以忽略性能差异
  • 红黑树的插入删除比AVL树更便于控制操作
  • 红黑树整体性能略优于AVL树,红黑树旋转情况少于AVL树

5、对旋转的基本理解 

在数据结构中,旋转是一种常见的操作,用于调整树或其他数据结构的结构以保持平衡或满足某些性质。在红黑树、AVL树、二叉搜索树等数据结构中,旋转操作通常用于平衡树的结构,以确保高效的插入、删除和查找操作。旋转操作有两种基本类型:左旋和右旋

5.1、左旋

左旋是一种将某个节点的右子节点旋转上来的操作。它会将当前节点下移,并且将其右子节点提升为新的父节点。这可以用于解决树向右倾斜的情况,以保持树的平衡。左旋的基本步骤:

  • parent:30
  • subR:50
  • subRL:b
  1. subRL变成parent的右子树 
  2. parent变成subR的左子树
  3. subR变成新根

 5.2、右旋

  • 50为parent,30为subL,b为subLR 
  1. subLR变成parent的左子树 
  2. parent变成subL的右子树
  3. subL变成新根

5.3、代码展示




template<class K, class V>
void AVLTree<K, V>::RotateL(Node* parent)  //左旋
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
 
	parent->_right = subRL;
	subR->_left = parent;
 
	Node* parentParent = parent->_parent;
 
	parent->_parent = subR;
	if (subRL)
		subRL->_parent = parent;
 
	if (_root == parent)
	{
		_root = subR;
		subR->_parent = nullptr;
	}
	else
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subR;
		}
		else
		{
			parentParent->_right = subR;
		}
 
		subR->_parent = parentParent;
	}
 
}

template<class K, class V>
void AVLTree<K, V>::RotateR(Node* parent)  //右旋
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
 
	parent->_left = subLR;
	if (subLR)
		subLR->_parent = parent;
 
	Node* parentParent = parent->_parent;
 
	subL->_right = parent;
	parent->_parent = subL;
 
	if (_root == parent)   //parent就是根,无需向上调整
	{
		_root = subL;
		subL->_parent = nullptr;
	}
	else                  //parent不是根,继续向上调整
	{
		if (parentParent->_left == parent)
		{
			parentParent->_left = subL;
		}
		else
		{
			parentParent->_right = subL;
		}
 
		subL->_parent = parentParent;
	}
 
}

 6、红黑树的插入操作

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
  1. 按照二叉搜索的树规则插入新节点
  2. 检测新节点插入后,红黑树的性质是否造到破坏
因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何
性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连
在一起的红色节点,此时需要对红黑树分情况来讨论:
约定 :cur 为当前节点, p 为父节点, g 为祖父节点, u 为叔叔节点
  • 情况一: cur为红,p为红,g为黑,u存在且为红
  • 情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑
  • 情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑

6.1、情况一

情况一: cur为红,p为红,g为黑,u存在且为红

解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整

  1. 如果g是根节点,调整完后要将g变为黑色
  2. 如果g不是根节点,继续向上调整

6.2、情况二

情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑

解决方式:p为 g 的左孩子, cur p 的左孩子,则对g进行右单旋转;相反,
                  p为g 的右孩子, cur p的右孩子,则对g进行左单旋转
                  p、g 变色 --p 变黑, g 变红

6.3、情况三

情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑
解决方式:p为 g 的左孩子, cur p 的右孩子,则针对 p做左单旋转,再对g进行右单旋转;相反,
                  p为g 的右孩子, cur p 的左孩子,则针对 p做右单旋转,再对g进行左单旋转

6.4、插入代码展示

template<class K, class V>
bool RBTree<K,V>::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;
		cur->_parent = parent;
	}
	else
	{
		parent->_left = cur;
		cur->_parent = parent;
	}

	while (parent && parent->_col == RED)
	{
		Node* grandfather = parent->_parent;
		if (parent == grandfather->_left)
		{
			//     g
			//   p   u
			// c
			Node* uncle = grandfather->_right;
			if (uncle && uncle->_col == RED)
			{
				// 变色
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				// 继续往上更新处理
				cur = grandfather;
				parent = cur->_parent;
			}
			else
			{
				if (cur == parent->_left)
				{
					// 单旋
					//     g
					//   p
					// c
					RotateR(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else
				{
					// 双旋
					//     g
					//   p
					//     c
					RotateL(parent);
					RotateR(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}

				break;
			}
		}
		else  // parent == grandfather->_right
		{
			//     g
			//   u   p 
			//          c
			//
			Node* uncle = grandfather->_left;
			if (uncle && uncle->_col == RED)
			{
				// 变色
				parent->_col = uncle->_col = BLACK;
				grandfather->_col = RED;

				// 继续往上处理
				cur = grandfather;
				parent = cur->_parent;
			}
			else
			{
				if (cur == parent->_right)
				{
					RotateL(grandfather);
					parent->_col = BLACK;
					grandfather->_col = RED;
				}
				else
				{
					//     g
					//   u   p 
					//     c
					//
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}

				break;
			}
		}
	}

	_root->_col = BLACK;

	return true;
}

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

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

相关文章

基于LDA主题分析的《老友记》情景喜剧数据集的建模分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

进程状态和优先级

文章目录 进程状态Linux中具体的进程状态僵尸进程孤儿进程 进程优先级 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 进程状态 进程在操…

图解算法数据结构-LeetBook-数组03_除本身之外乘积

为了深入了解这些生物群体的生态特征&#xff0c;你们进行了大量的实地观察和数据采集。数组 arrayA 记录了各个生物群体数量数据&#xff0c;其中 arrayA[i] 表示第 i 个生物群体的数量。请返回一个数组 arrayB&#xff0c;该数组为基于数组 arrayA 中的数据计算得出的结果&am…

AI驱动的软件测试,何时可以信赖?

综合编译&#xff5c;TesterHome社区 作者&#xff5c;Yuliya Vasilko&#xff0c;数据工程师 以下为作者观点&#xff1a; 越来越多的组织转向人工智能&#xff08;AI&#xff09;驱动的测试解决方案&#xff0c;以简化质量保证流程并提高软件可靠性。 随着对人工智能的依赖程…

动态规划题解

文章目录 杨辉三角杨辉三角2爬楼梯最小花费爬楼梯斐波那契数列比特位计数不同路径 杨辉三角 var generate function(numRows) {//先定义一个空数组var ret[];//遍历行数for(let i 0;i<numRows;i){var cownew Array(i1).fill(1)//定义行内数组数&#xff0c;有多少numrows&a…

[N-133]基于springboot,vue小说网站

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plus 本项…

幼教早教内容付费预约小程序的效果如何

很多家庭对孩子的重视程度很高&#xff0c;尤其加之如今激烈竞争的市场&#xff0c;孩子从小便需要各种提前教育&#xff0c;而相关教培企业也比较多&#xff0c;基于服务高需求度&#xff0c;线下教育与线上课程教育同样重要。 在实际经营中&#xff0c;幼教早教培训机构也面…

关于我用半个月过了软件设计师这件事

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 前言 有关考取软件设计师证书的好处我就不在…

JAIN SIP API详解与GB28181服务器实现

目录 JAIN SIP API 摘要 关于JAIN SIP API API概述 maven坐标 类/接口 Message接口 Request接口 Response接口 即时通讯程序 TextClient代码概述 Message Processor SIP协议栈 发送SIP请求 发送会话消息 接收SIP响应 接收SIP请求 处理错误 总结 GB28181SIP…

HDRP图形入门:HDRP渲染管线depth翻转

新项目开坑HDRP渲染管线&#xff0c;花了些时间把项目开发框架和图形工作流更新到最新版本&#xff0c;其间发现HDRP中深度信息和buildin渲染管线翻转了。 以前的buildin渲染管线&#xff0c;距离摄像机越近depth->0&#xff0c;越远depth->1&#xff0c;这也很好理…

2.3 CE修改器:浮点数扫描

本关需要使用 Cheat Engine 工具对浮点数进行扫描&#xff0c;完成修改任务。浮点数是一种带有小数点的数值&#xff0c;通过“浮点数”扫描方式进行修改。本关中&#xff0c;健康值为单精度浮点数&#xff0c;弹药值为双精度浮点数&#xff0c;需要将这两项数值都修改为 5000 …

【Linux】八、进程通信

进程通信的介绍 目的 数据传输&#xff1a;一个进程将它的数据发送给另一个进程&#xff1b; 资源共享&#xff1a;多个进程间共享资源&#xff1b; 通知事件&#xff1a;一个进程向另一个或一组进程发送消息&#xff0c;同时事件如&#xff0c;进程终止时要通知父进程&#xf…

web前端开发第一次Dreamweave课堂练习/html练习代码《社会主义核心价值观》

目标图片&#xff1a; 文字素材&#xff1a; 社会主义核心价值观 Socialist Core Values 富强、民主、文明、和谐是国家层面的价值目标。 自由、平等、公正、法治是社会层面的价值取向。 爱国、敬业、诚信、友善是公民个人层面的价值准则。 Core socialist values are the…

联系作者方式的教程

首先你应该目前是在付费资源运行效果的展示文章页面&#xff0c;如下所示 然后一直往下滑&#xff0c;滑到这个文章的最下面&#xff0c;就可以看到我的推广名片&#xff0c;最后点击这个名片就可以获取到我的联系方式了~

[云原生案例2.4 ] Kubernetes的部署安装 【通过Kubeadm部署Kubernetes高可用集群】

文章目录 1. 基本架构及前置准备1.1 基本架构1.2 前置准备 2. 系统初始化操作 ---- 所有节点2.1 关闭防火墙、selinux和swap分区2.1.1 关闭防火墙和selinux2.1.2 关闭交换分区 2.2 修改主机名&#xff0c;添加域名映射2.2.1 修改主机名2.2.2 修改本地hosts文件 2.3 内核升级2.4…

MGA-WPA

作者未提供代码

YOLO目标检测——水果检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;水果分类检测数据集的应用场景主要包括农贸市场监管、水果品质检测、超市零售管理等数据集说明&#xff1a;水果分类检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含有苹果香蕉橙子图片标签说明&#xff1a;使…

【Servlet】 三

本文主要介绍了基于serlvet的表白墙项目的编写. (附完整代码) 一.JS基础 作为后端开发,对于前端的要求是能前端代码能看懂七七八八 . JS是一个动态弱类型的编程语言 1. let/war定义变量 (推荐使用let) 2.querySelector是浏览器提供api , 能够获取到页面的元素的 (js的目的就…

CV计算机视觉每日开源代码Paper with code速览-2023.11.9

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【3D目标检测】3DiffTection: 3D Object Detection with …

JAVA毕业设计110—基于Java+Springboot+Vue的房屋租赁系统小程序(源码+数据库)

基于JavaSpringbootVue的房屋租赁系统小程序(源码数据库)110 一、系统介绍 本系统前后端分离 本系统分为用户、房东、超级管理员三种角色 1、用户&#xff1a; 登录、注册、房屋搜索、房屋收藏、看房预约、租房申请、租房记录、看房记录、收藏记录、我的消息、个人信息修改…