红黑二叉树详解及理论分析

article/2025/10/1 4:47:55

发表于我的博客网站(prajna.top): http://prajna.top/doc/2/175

什么是红-黑二叉树?

  红-黑二叉树首先是一颗二叉树,它具有二叉树的所有性质,是一种平衡二叉树。普通二叉树在生成过程中,容易出现不平衡的现象,即使是使用随机算法生成二叉树,也是有一定概率生成不平衡的二叉树. 如下图所示 :

                                                        

为了解决二叉树的不平衡问题,“大牛”们终于研究出了 红-黑二叉树(red-black binary tree),它总是生成像左图那样的平衡二叉树。

 

   红-黑二叉树的数据结构

  1)叶子节点(leaf child),和 内部节点(internal node)

     红黑二叉树的每个节点都增加了2个指针,叫做 leaf child,它永远存在,而且永远都是 child,原二叉树节点,叫做 internal node。

  2) 左旋,右旋, 重新着色(recolor)

       左旋,右旋, 重新着色(recolor) 是红-黑二叉树的三个基本操作。

   3) 规则

      3.1) 根节点和 叶子节点(leaf child) 节点必须是黑节点, 内部节点(internal node)非黑即红。

      3.2) 从根节点开始到每条子路径的叶子节点(leaf child),所有的黑节点数目相同。

      3.3)  红节点的父亲节点必须是黑节点。

      tree 1是一个标准的红-黑树,每条的路径的黑节点数量都是 3。 tree 2和 tree 4是 tree 3 分别左旋,右旋后的结果。

       recolor 操作,设想一下树 tree 1,可以把B节点 改变成红色,D和E改变成黑色,这颗红-黑树同样成立,这个操作就是 recolor。

   

   红-黑二叉树的设计思想

    如果不了解红-黑树的设计思想,死套相应的操作规则,是件很头疼的事情,知其然而不知其所以然,也是工程师的大忌。可惜,在网上找了不少资料,都介绍红-黑树的工作流程。在这里,我大胆地猜想一下红黑树的设计思想。

    红-黑树的设计思想应该是,利用 红-黑这两种节点颜色来追踪二叉树的平衡状况, 重新着色(recolor)这个操作就是动态刷新各节点颜色,如果发现树开始出现不平衡状况,就使用 左旋(left rotate)或者右旋(right rotate)来改变树的结构。 把图(tree 2) 和(tree 3) 反过来看,它们都是不平衡树,对 (tree 2)进行右旋,或对(tree 4)进行左旋都能得到(tree 3)这样的平衡树。 左旋的实质是增加左树的高度而减少右树的高度,右旋反之。 这样交替运用这三个操作,我们就可以构建一颗平衡的二叉树。

 

   插入

    通过上面对设计思想的分析,插入的工作流程就非常简单了。

    首先分析 父亲节点 和 叔叔节点的颜色,判断“父亲”和“叔叔”的势力是否平衡。如果平衡,则直接插入,然后进行recolor 操作,继续最踪插入后的情况。否则把"爷爷这颗子树"(父亲节点,爷爷节点 和 叔叔节点)左(右)旋以后再插入。

          如何判断"爷爷"这颗子树是否平衡呢?

          这就是红-黑树的核心了,通过 "父亲"与"叔叔"的颜色来判断。如果他们同时为红色或者黑色,那么"爷爷"这颗子树是平衡的。否则,就不平衡。需要进行旋转操作来平衡

这两者的势力。

  

   按照 红-黑树的规则,根节点 30 必须是黑色,然后,我们插入 20,为了不违反各分支,黑节点数相等的原则,20必须是红色,接着再插入 红色节点40,so good, so far. 现在 插入 节点11。现在问题出来了,按照红节点必要有黑父亲的规则, 11 和 20 出现了冲突, 这种情况下,需要进行 recolor 操作: 20 和 40 调整为黑色,同时把 11 的爷爷 30 调整为红色,这样可以保证 30 这颗子树的黑节点数目不变。 如果 30 的父亲节点恰好也是红色,需要执行 插入红色节点 30,如果 30的父亲是黑节点,调整结束,如果 30是根节点根据规则,把它改成 黑节点,此时,各分支节黑点数 +1变成了2,数目仍然相等。如果插入的数据是平衡的,我们只需要重复执行,上述操作,插入红节点,recolor。

 

   继续插入 71, 发现 71的父亲 62 这个节点没有兄弟节点,很明显以71的爷爷40作为根节点子树,已经不平衡了,因为,平衡的情况应该是,62 有一个 红色的兄弟节点——这样的话,我们只需要递归执行 recolor 即可。 可惜,62没有兄弟,于是,左旋一下 (40-62-71) 这颗树,左旋以后, 黑色根节点40变成了孩子节点,需要把的黑色上提,同新的根节点62交换颜色,以保证 黑色节点数目不变。 就这样交替执行下去,我们就会得到一颗平衡的二叉树。

 

  继续 插入 65,recolor 40, 71, 62这三个节点。 OK,我们继续插入 78,64, 当插入64需要 recolor 65, 78 71 三个节点。 recolor 以后, 71 与 62同为红色节点,违反了规则,此时,执行一个递归算法,把71当成一个新接点插入。 现在让我们来插入新节点 71,由于 62 与 20颜色不相同, 30为根节点的这颗树不平衡,需要左一个 左旋的操作。

同时 62 与30 互换颜色。 现在,71的父亲为根节点,递归结束,71 插入成功。

   上面的演示,包含了所有的插入的基本情况。 总结一下:

   1)插入的新节点,总是红节点。

   2)  如果 插入出现红节点冲突:

         1)父亲,叔叔都是红节点,表明树处于平衡状态,执行重新着色(recolor)操作,否则进行旋转操作。

         2) 把新的爷爷节点(子树根节点)当成一个新的节点, 插入该树。 重新执行,插入新节点的操作。

   具体的 伪代码,很多地方都右介绍,我就不多说了。 伪代码里面,把插入的各种状况分得很细——一些变化的中间状态,也当成了一个插入状态,只是编程的需要,理论上,

从我们的刚才的分析中可以得出,实际的插入就2个状态,平衡 or 不平衡——通过父亲与叔叔的颜色来判断。 平衡就recolor,不平横就 rotate. 千万不要被代码的分析给迷惑住了。

 

     删除

      首先执行的是二叉树的通用删除方法, 找被删节点M的子节点C来替换它,而不是直接删除M,M被C替换后,删除C即可!这样就把一个删除 父亲节点的问题,转变成了删除子节点的问题。 子节点C的选择原则是, 取右分支最左边,或者 左分支最右边的。 这样,我们只需要研究 子节点C的删除情况,子节点C 最多有一个孩子节点(C 是最左边或者最右边)。

     如下图 d-1所示,要删除M节点,可以先用 C或者D替换M,然后,在删除C或者D。

     红-黑二叉树删除节点,最大的麻烦是要保持 各分支黑色节点数目相等。 因为是删除,所以不用担心存在颜色冲突问题——插入才会引起颜色冲突。

 

     1) 直接删除。

       1.1) M节点是红节点,直接删除。图 d-2. M不可能带有其它子节点——如子节点为黑,则违反黑节点数原则,为红,则违反“颜色”原则。                

       1.2) M节点是黑节点带有红色子节点直接用子节点,则recolr 子节点为黑,替换M。

    2)  M节点无子节点,且与  P 节点同为黑色。

         如果删除M则分支 P的黑节点数肯定 少一个,如果M有子节点,就直接用子节点顶上来(情况1)。现在只右考察一下M的兄弟N,如果它是红色节点,那就好办了,

利用 插入时 reclor逆操作,把红节点变成黑节点,保持黑节点数目不变。

       先是进行一个左旋, 把红节点当作新的根节点,然后,recolor,此时,P为红,M和N1则为黑, 最后,再此 recolor, 把 M和N1变红,P 变黑,现在可以直接删除M了。

其实,仔细观察一下,会发现它是 插入 recolor的逆过程。

       OK,现在我们利用 红节点变黑, 删除了一个黑节点。保持了黑节点数目不变的原则。

       如果 M 节点的兄弟节点是也是黑节点怎么办呢?

       这种情况,把M的兄弟S recolor 为红,P节点分支减少一个 黑节点数, 然后,再把 P节点当作当前节点,递归"删除",直到其它分支,也都recolor一个黑节点为红节点,使黑节点数保持相同。

     :“删除”加了引号,这个删除不是指从树中移除——这个过程是在最开始通过子节点替换完成的——而是指递归 recolor 一个黑节点。

    

        先recolor M的兄弟N,然后,“删除” 当前节点P,  recolor p的兄弟 A3, 再"删除"  A1,recolor A2,依次递归向上,每个分支减少一个 黑节点。

        这里的 递归删除 根节点 P,并不是真正意义上面的删除,不同于删除节点M,只是为了重用代码的结构而已。

       一些文章的伪代码里面,把删除也分成了好多种情况,其实 理论上就三种。 1) 直接删除。 2) 旋转,recolor 红节点成黑节点。 3) 递归,recolor 黑节点为红节点。

 

      后记

       这两天研究 红-黑树,到网上查了好多资料,都是讲述的操作流程,没有文章讲一下算法的思想。看得人一头雾水。我花了些时间,仔细研究了一下,感觉还是蛮简单的。

真的很佩服算法的设计者。写出来供大家研究一下。

 

      参考资料

     1)   http://en.wikipedia.org/wiki/Red%E2%80%93black_tree

     2)   算法导论。

     3)  google 了一些文章。

 

        

 


http://chatgpt.dhexx.cn/article/sPUESKhr.shtml

相关文章

二叉树到红黑树

二叉树查找树 又叫二叉排序树。二叉查找树或者是一棵空树,或者是一棵具有如下性质的二叉树: 对于任何一个结点X若它的左子树非空,则左子树上所有结点的值均小于等于X的值;若它的右子树非空,则右子树上所有结点的值均大…

详解c++---红黑二叉树的原理和实现

目录标题 什么是红黑二叉树树红黑树的性质红黑树的效率分析红黑树的准备工作红黑树的insert函数节点的调整情况一情况二情况三 转换的实现打印函数find函数检查函数 什么是红黑二叉树树 avl树是通过控制平衡因子来控制二叉搜索树的平衡,当某个节点的平衡因子等于2或…

红黑树和二叉树有什么区别?

红黑树和二叉树有什么区别? 什么是二叉树?什么是红黑树? 二叉树(Binary Tree)是指每个节点最多只有两个分支的树结构,即不存在分支大于 2 的节点,二叉树的数据结构如下图所示 这是一棵拥有 6 …

二叉树系列:红黑树

介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树。红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。除了…

红黑树结构原理的图文讲解(非代码)

1.引言 HashMap的基本结构是数组,链表和红黑树。以数组为基本形态,数组中的元素先以链表形式储存,当链表的长度超过8时(包含数组上的那个链表头)就会将链表转换为红黑树,以加快修改和查询效率。当然除了Ha…

二叉树与红黑树见解

目录 一、红黑树简介二、 红黑树的特性三、红黑数的应用四、红黑树的原理实现4.1 识别红黑树4.2 红黑树节点的旋转4.3 插入节点4.3.1分情况讨论:4.3.2 代码示例 4.4删除节点相关引用 一、红黑树简介 红黑树是一种自平衡的二叉查找树,是一种高效的查找树…

什么是红黑树(内存最优的二叉树)

一.红黑树定义 红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。 它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1…

【二叉树进阶】红黑树(Red Black Tree) - 平衡二叉搜索树

文章目录 一、红黑树的概念二、红黑树的性质2.1 红黑树和AVL树效率对比 三、红黑树的结构(KV模型)四、红黑树的插入4.1 插入节点4.2 平衡化操作(难点)4.2.1 情况一4.2.2 情况二4.2.3 情况三 4.3 总结 五、红黑树的验证六、红黑树的…

MySQL 慢查询日志导入 Elasticsearch 可视化查询分析

当应用程序后台 SQL 查询慢的时候我们一般第一时间会查看数据库慢查询记录,但是慢查询记录是原始文本,直接查询搜索分析比较费时费力,虽然业界有针对 MySQL 慢查询分析的命令行工具(比如:pt-query-digest)&…

MySQL 慢查询日志如何查看及配置

简介 MySQL 慢查询日志是排查问题 SQL 语句,以及检查当前 MySQL 性能的一个重要功能。 查看是否开启慢查询功能: 说明: slow_query_log 慢查询开启状态 slow_query_log_file 慢查询日志存放的位置(这个目录需要MySQL的运行帐号的…

MySQL高级篇——聊聊MySQL的慢查询日志

文章目录: 1.数据库服务器的优化步骤 2.查看系统性能参数 3.定位执行慢的 SQL:慢查询日志 4.查看 SQL 执行成本:SHOW PROFILE 1.数据库服务器的优化步骤 当我们遇到数据库调优问题的时候,该如何思考呢?这里把思考…

清理mysql慢查询日志_MySQL清理慢查询日志slow_log的方法

一、清除原因 因为之前打开了慢查询,导致此表越来越大达到47G,导致磁盘快被占满,使用xtrabackup进行备份的时候文件也超大。 mysql> show variables like log_output%; Connection id: 1694401091 Current database: mysql +---------------+-------+ | Variable_name | …

mysql 慢查询日志的设置与优化

目录 1 引言 2 慢查询日志配置 3 分析工具 1 引言 MySQL数据中有记录慢查询的一种手段。并且是MySQL自带的。可用来排查那些查询sql语句执行得慢。从而给开发者提供一个调优得依据。 MySQL 慢查询的相关参数解释: slow_query_log :是否开启慢查…

如何开启mysql慢查询日志?

1、查看mysql的慢查询日志是否开启 show variables like %query%; 可以看到slow_query_log的值是OFF,也就是mysql默认是不启用慢查询日志的。 这里还有个long_query_time,默认是10秒,也就是超过了10秒即为慢查询。 log_queries_not_using_…

MySQL慢查询日志详解

本次代码执行环境的mysql版本是 :5.6.37-log 1.慢查询日志概念(也叫慢日志):在 MySQL 中执行时间超过指定时间的 SQL 语句 2.常见的几个相关的变量 (可以直接去mysql下的配置文件my.cnf文件中去改,我下面是直接在SQLyog中进行操作) 默认情况下慢查询日志是关闭的…

MySQL 慢查询日志 使用方法浅析 日志定位与优化技巧

目录 前言 1、如何开启使用慢查询日志? 1.1 开启慢查询日志 1.2 设置慢查询阈值 1.3 确定慢查询日志的文件名和路径 1.3.1 查询MySQL数据目录 1.3.2 查询慢查询日志文件名 1.3.3 查询全局设置变量 1.3.4 查询单个变量命令 1.3.5 其他注意事项 2、如何定位并优…

mysql慢查询日志在哪里

如何查找MySQL中查询慢的SQL语句 你是指慢查询日志吗? 在my.ini中加上下面两句话 log-slow-queriese:\mysql5.5\mysql_slow_query.log long_query_time10 前面一句是设置慢查询日志存放路径,第二句是指多少秒以上算慢查询,上面的语句&#xf…

MySQL慢查询日志分析

(1)慢查询日志 MySQL提供了慢SQL的日志记录功能,我们可以通过设置一些属性来记录系统使用过程中慢查询的执行日志。使用MySQL慢查询日志对有效率问题的SQL进行监控。 查看属性 【1】查看MySQL是否开启慢查询日志记录功能 show variables l…

MySQL优化之慢日志查询

目录 一、慢查询日志(slow_query_log)概念二、慢查询日志实践1. 打开慢查询日志开关2. 设置合理的、业务可以接受的慢查询时间上限long_query_time3. 压测执行各种业务4. 查看慢查询日志5. 用explain分析这些耗时的sql语句,从而针对性优化 三、show profiles查看sql…

MySQL日志(一)—— 慢查询日志slow log

一、慢查询日志(slow log) 慢查询日志,就是查询超过一定的时间没有返回结果的时候,MySQL会将执行的SQL记录到日志中,这个日志,就称为慢查询日志。通过分析慢查询日志,可以快速找出执行慢的SQL语…