数据结构与算法:红黑树讲解

关于红黑树, 这篇讲的更详细易懂。

https://www.cnblogs.com/jakelin/p/14324966.html

一颗平衡的二叉搜索树的任意节点平均查找效率为树的高度h,即O(lgn)

但是如果二叉搜索树的失去平衡(元素全在一侧),搜索效率就退化为O(n),因此二叉搜索树的平衡是搜索效率的关键所在。

    为了维护树的平衡性,数据结构内出现了各种各样的树,比如AVL树通过维持任何节点的左右子树的高度差不大于1保持树的平衡,而红黑树使用颜色的概念维持树的平衡,使二叉搜索树的左右子树的高度差保持在固定的范围。

     相比于其他二叉搜索树树,红黑树对二叉搜索树的平衡性维持有着自身的优势。

    红黑树是一种自平衡二叉搜索树,它通过对节点进行着色(红色或黑色)并在树的操作过程中维护一系列性质,以确保树大致保持平衡。这种平衡确保了树的搜索、插入和删除操作的最坏情况时间复杂度为O(log n),其中n是树中元素的数量。

红黑树的定义

1.节点非红即黑。

2.根节点是黑色。

3.所有NULL结点称为叶子节点,且认为颜色为黑。

4.所有红节点的子节点都为黑色。

5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

红黑树数据结构

template<class T>class rb_tree_node{    

  typedef  rb_tree_node_color  node_color;    
  typedef  rb_tree_node<T>  node_type;


public:    
node_color color;//颜色    
node_type* parent;//父节点    
node_type* left;//左子节点    
node_type* right;//右子节点    
T value;//值    
....
};

红黑树插入节点

特殊情况考虑完成之后,下面假设又开始添加节点,我们面对的第一个问题是新增加的节点是标记成红色还是黑色?显然无论是新插入的节点是黑色或者是红色,红黑树限制1,2,3一定是满足的,那么如果将新插入的节点标识成黑色的话,可能违反5,但是如果将新插入的节点标识成红色,肯能违反4,看似好像是两个是类似的。

情况 1.  如果插入的节点是根节点(初始的红黑树为空)

直接将该节点颜色改成黑色。

情况 2.  插入结点的Key已经存在

直接更换节点的值。

情况 3.  插入的节点的父节点是黑色

插入的节点不是红黑树的根节点,如果新插入的节点的父节点是黑色的话,红黑树不需要调整,直接插入。

情况 4. 插入节点的父节点是红色

根结点是黑色。如果插入的父结点为红结点,那么该父结点不可能为根结点,所以插入结点总是存在祖父结点。

情况4.1  插入节点的父节点是红色,叔叔节点是黑色

4.1.1 父节点和祖父节点在一条线上。

需要旋转(左旋/右旋)后变色

4.1.2 父节点和祖父节点不在一条线上。

首先调换位置,然后旋转(左旋/右旋)后变色。

情况4.2 父节点是红色,叔叔节点是红色

首先,交换祖父节点和叔叔节点的颜色。

如果通过这样做使得祖父节点成为了双重红色(祖父节点的父节点也是红色)

则需要对祖父节点进行进一步的操作,可能是旋转或者继续向上层进行重新着色和调整(进行递归的操作)。

红黑树删除节点

红黑树删除节点需要考虑节点的位置,删除节点后需要保持红黑树的平衡性。

二叉树删除结点找替代结点有3种情景:

情景1:若删除结点无子结点

直接删除。

情景2:若删除结点只有一个子结点

用子结点替换删除结点。

情景3:若删除结点有两个子结点

用后继节点(大于删除结点的最小节点)替换删除结点。

当然用前绩节点也可以,不过通常我们会用后继节点。

(把二叉树所有结点投射在X轴上,所有结点都是从左到右排好序的,所有目标结点的前后结点就是对应的前继和后继结点)

如果待删除节点有两个子节点,则不能将该节点直接删除,而是从其右子树中选取最小值节点(或左子树的最大值节点)作为删除节点。

三种情况 和二叉搜索树的节点删除完全相同。

一个重要的思路:删除结点被替代后,在不考虑结点的键值的情况下,对于树来说,可以认为删除的是替代结点。

基于此,上面所说的3种二叉树的删除情景可以相互转换并且最终都是转换为情景1。

情景2:删除结点用其唯一的子结点替换,子结点替换为删除结点后,可以认为删除的是子结点,若子结点又有两个子结点,那么相当于转换为情景3,一直转换,总是能转换为情景1。
情景3:删除结点用后继结点(后继结点肯定不存在左结点),如果后继结点有右子结点,那么相当于转换为情景2,否则转为为情景1。

渐近边界的证明

红黑树的查找效率与二叉搜索树的查找效率相同,即在最坏的情况下时间复杂度为O(log n),其中n是树中节点的数量。

这是因为红黑树保持了树的平衡性,即从根节点到最远的叶子节点的最长路径不会超过最短路径的两倍。这意味着树的高度大致保持在log n的数量级,因此查找效率很高。

为什么STL map和set使用红黑树而不是平衡二叉树?

红黑树提供的平衡程度与性能之间的折中。与平衡二叉树(特别是AVL树)相比,红黑树在维持平衡的严格性上做了妥协。

(1)红黑树是一种自平衡二叉搜索树,它通过对节点进行着色(红色或黑色)并在树的操作过程中维护一系列性质,以确保树大致保持平衡。这种平衡确保了树的搜索、插入和删除操作的最坏情况时间复杂度为O(log n),其中n是树中元素的数量。

(2)AVL树是高度平衡的二叉搜索树,对平衡的要求更严格,任何时候任何节点的两个子树的高度差最多为1。

    这种高度的平衡确保了极佳的查找性能,但是在插入和删除操作时可能需要更频繁的旋转来维持这种严格的平衡,导致这些操作相对于红黑树来说更加耗时。它不像AVL树那样对平衡有严格的要求,因此在插入和删除操作时通常需要较少的旋转,这可以在实际应用中提供更好的性能。在频繁的插入和删除操作时,红黑树较少的旋转次数意味着整体的性能往往更优。


 

参考:

https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91

https://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html

https://www.cnblogs.com/fanzhidongyzby/p/3187912.html

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

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

相关文章

牛客周赛 Round 33 解题报告 | 珂学家 | 思维场

前言 整体评价 感觉这场更偏思维&#xff0c;F题毫无思路&#xff0c;但是可以模拟骗点分, E题是dij最短路. A. 小红的单词整理 类型: 签到 w1,w2 input().split() print (w2) print (w1)B. 小红煮汤圆 思路: 模拟 可以从拆包的角度去构建模拟 注意拆一包&#xff0c;可以…

如何增加层次厚度?

Q 老师&#xff0c;我在做一个斧头武器&#xff0c;如何在平面上增加厚度和层次呢&#xff1f; A 选中这几个线&#xff0c;点连接就会出现中线&#xff0c;把中线稍作调整即可~

Springboot+vue的社区医疗综合服务平台(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的社区医疗综合服务平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的社区医疗综合服务平台&#xff0c;采用M&#xff08;m…

数据分析这么卷吗!AI几分钟做完我半天的工作,这让人怎么办!

随着AI技术的飞速发展&#xff0c;人工智能领域正在经历一场前所未有的革命。无论是ChatGPT还是谷歌的巴德&#xff0c;以及国内诸如文心一言、ChatGLM等产品的涌现&#xff0c;都在不断地证明着这一点。这些技术不仅在推动着各行业的发展&#xff0c;更在不断地改变着我们的生…

Redis如何修改key名称

点击上方蓝字关注我 近期出现过多次修改Redis中key名字的场景&#xff0c;本次简介一下如何修改Redis中key名称的方法。 1. 命令行方式修改在Redis中&#xff0c;可以使用rename命令来修改Key的名称。这个命令的基本语法如下&#xff1a; RENAME old_key new_key 在这里&#…

详细分析Pandas中的Series对象(附Demo)

目录 1. 问题所示2. 基本知识3. API Demo4. 示例Demo5. 彩蛋 1. 问题所示 从实战上手基础知识 一开始遇到这个Bug&#xff1a; TypeError: unsupported operand type(s) for -: str and float后面经了解执行减法运算时发生了错误&#xff0c;其中一个操作数是字符串类型&…

继承(extends)

继承[extends] 继承的好处继承的示意图继承的使用细节JVM的内存&#xff1a;继承的内存布局 继承的好处 1&#xff09;提高代码的复用性 2&#xff09;代码的扩展性和维护性提高了 继承的示意图 继承的使用细节 1&#xff09;子类继承了所有属性和方法&#xff0c;非私有的…

liunx前后端分离项目部署

文章目录 1、nginx的安装和自启动2.nginx负载均衡3.前后端项目部署-后端部署4.前后端项目部署-前端部署 1、nginx的安装和自启动 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel1.安装我们nginx所需要的依赖 wget http://nginx.org/download/nginx-1.…

线程池的常用实现及执行流程

线程池 线程池线程池接口线程池参数线程池分类动态数目线程池固定数目线程池单例线程池任务调度线程池 线程池的执行流程 线程池 线程池接口 线程池参数 1、corePoolSize&#xff1a;核心线程数&#xff0c;线程池中最少线程&#xff0c;核心线程不会被回收。 2、maximumPoo…

做接口测试的流程一般是怎么样的?UI功能6大流程、接口测试8大流程这些你真的全会了吗?

在讲接口流程测试之前&#xff0c;首先需要给大家申明下&#xff1a;接口测试对于测试人员而言&#xff0c;非常非常重要&#xff0c;懂功能测试接口测试&#xff0c;就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试&#xff0c;一般也是面试笔试必问。为方便大家更…

自定义搭建管理系统

最近使用自己搭建的脚手架写了一个简易管理系统&#xff0c;使用webpackreactantd&#xff0c;搭建脚手架参考&#xff1a; 使用Webpack5搭建项目&#xff08;react篇&#xff09;_babel-preset-react-app-CSDN博客 搭建的思路&#xff1a; 1. 基建布局&#xff0c;使用antd的…

Linux调用可执行程序:system()函数和execl函数

system()函数&#xff1a; system()函数是一个在C/C编程语言中的库函数&#xff0c;用于在操作系统中执行命令。 函数声明如下&#xff1a; int system(const char *command);该函数接受一个指向以空字符结尾的字符串的指针作为参数&#xff0c;该字符串包含要执行的命令。函…

[ai笔记12] chatGPT技术体系梳理+本质探寻

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第12篇分享&#xff01; 这周时间看了两本书&#xff0c;一本是大神斯蒂芬沃尔弗拉姆学的《这就是ChatGPT》,另外一本则是腾讯云生态解决方案高级架构师宋立恒所写的《AI制胜机器学习极简入门》&#xf…

OpenHarmony Docker移植实践

Docker简介 从操作系统诞生之日起&#xff0c;虚拟化技术就不断的演进与发展&#xff0c;结合目前云原生的发展态势&#xff0c;容器无疑是其中的重要一环。 Docker是一个开源的软件项目&#xff0c;可以在Linux操作系统上提供一层额外的抽象&#xff0c;让用户程序部署在一个…

单日收益四位数的Ai姓氏头像项目

单日收益四位数的Ai姓氏头像项目 发布时间&#xff1a;2024-02-24 00:00:00作者&#xff1a;傲战浏览&#xff1a;未知分类&#xff1a;教程网朗读&#xff1a; 最近利用AI一键生成头像的这个项目又火起来了,据说一天直播间光礼物就能收到大几千 操作起来没什么难度,一键生成 …

HarmonyOS-ArkTS卡片运行机制和相关模块

ArkTS卡片运行机制 实现原理 图1 ArkTS卡片实现原理 卡片使用方&#xff1a;显示卡片内容的宿主应用&#xff0c;控制卡片在宿主中展示的位置&#xff0c;当前仅系统应用可以作为卡片使用方。卡片提供方&#xff1a;提供卡片显示内容的应用&#xff0c;控制卡片的显示内容、…

LeetCode--代码详解 235.二叉搜索树得最近公共祖先

235.二叉搜索树得最近公共祖先 题目 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可…

nginx------------- 变量 日志分割 自定义图标 证书 (四)

一、高级配置 1 .1网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机…

RunnerGo五种压测模式你会配置吗?

我们在做性能测试时需要根据性能需求配置不同的压测模式如&#xff1a;阶梯模式。使用jmeter时我们需要安装插件来配置测试模式&#xff0c;为了方便用户使用&#xff0c;RunnerGo内嵌了压测模式这一选项&#xff0c;今天给大家介绍一下RunnerGo的几种压测模式和怎么根据性能需…

使用GPT生成python图表

首先&#xff0c;生成一脚本&#xff0c;读取到所需的excel表格 import xlrddata xlrd.open_workbook(xxxx.xls) # 打开xls文件 table data.sheet_by_index(0) # 通过索引获取表格# 初始化奖项字典 awards_dict {"一等奖": 0,"二等奖": 0,"三等…