红黑树原理详解

article/2025/11/3 15:42:25

红黑树原理详解

    • 红黑树的旋转
    • 红黑树上结点的插入
    • 红黑树上结点的删除

参考:
教你初步了解红黑树
红黑树(一)之 原理和算法详细介绍

红黑树定义:
(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

如下图,是一颗简单的红黑树。其中Nil为叶子结点,并且它是黑色的
在这里插入图片描述

黑高度
从某个节点x出发(不包含该该节点)到达一个叶子节点的任意一条路径上,黑色节点的个数称为该节点x的黑高度,用bh(x)表示。从该结点出发的所有下降路径都具有相同的黑节点个数。
红黑树黑高度的定义为其根节点的黑高度。

性质
一棵含有n个内节点的红黑树的高度至多为2log(n+1).
即,包含n内结点的红黑树是高度为O(lgn)的查找树,简单操作的运行时间为O(lgn)。

证明
首先定义一个节点x的黑高为 b h ( x ) bh(x) bh(x),表示从x到任意一个叶子节点路径上黑色节点的个数(不包括x)。

1.第一步,先证明以某一节点x为根的子树中至少包含 2 b h ( x ) − 1 2^{bh(x)}−1 2bh(x)1个内节点(不是叶子的都是内节点)。用数学归纳法证明。
如果x的高度为0,那么x是叶节点,包含0个内节点,满足该式子。
对于高度为正值的x,其两个孩子至少包含 2 b h ( x ) − 1 − 1 2^{bh(x)−1}−1 2bh(x)11个内节点,
所以以x为根的子树至少包含 ( 2 b h ( x ) − 1 − 1 ) + ( 2 b h ( x ) − 1 − 1 ) + 1 = 2 b h ( x ) − 1 (2^{bh(x)−1}−1)+(2^{bh(x)−1}−1)+1=2^{bh(x)}−1 (2bh(x)11)+(2bh(x)11)+1=2bh(x)1个内节点。

2.第二步,对于一棵高度为h的树,任意一条从根到叶节点(不包括根)的路径上至少有一半黑色节点,从而 b h ( x ) ≥ h / 2 bh(x)≥h/2 bh(x)h/2,所以 n ≥ 2 b h ( x ) − 1 ≥ 2 h / 2 − 1 n≥2^{bh(x)}−1≥2^{h/2}−1 n2bh(x)12h/21,即 h ≤ 2 l o g ( n + 1 ) h≤2log(n+1) h2log(n+1)

红黑树的旋转

直接看这里
https://www.cnblogs.com/skywang12345/p/3245399.html

红黑树上结点的插入

STL源码剖析—红黑树原理详解上

1、黑父
如下图所示,如果新节点的父结点为黑色结点,那么插入一个红点将不会影响红黑树的平衡,此时插入操作完成。红黑树比AVL树优秀的地方之一在于黑父的情况比较常见,从而使红黑树需要旋转的几率相对AVL树来说会少一些。
在这里插入图片描述

2、红父
如果新节点的父结点为红色,这时就需要进行一系列操作以保证整棵树红黑性质。如下图所示,由于父结点为红色,此时可以判定,祖父结点必定为黑色。这时需要根据叔父结点的颜色来决定做什么样的操作。青色结点表示颜色未知。由于有可能需要根结点到新点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点(我们可将其视为新点)都不一样。所以我们在此使用一个蓝色箭头指向这个起始点,并称之为判定点。
在这里插入图片描述

2.1 红叔
当叔父结点为红色时,如下图所示,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上(迭代)进行平衡操作

这种称为LLr型,(表示祖父的左孩子L的左孩子L,同时叔叔是红色r),下面名称可以类比。
在这里插入图片描述
需要注意的是,无论“父节点”在“叔节点”的左边还是右边,无论“新节点”是“父节点”的左孩子还是右孩子,它们的操作都是完全一样的(其实这种情况包括4种,只需调整颜色,不需要旋转树形)。

其实还有LRr型(在父节点处左旋则可得到LLr型),不要讨论了。
RLr型(与LRr型对称),RRr型(与LLr对称),这两种对称情况也不用讨论了。

2.2 黑叔
当叔父结点为黑色时,需要进行旋转,以下图示了所有的旋转可能:
Case 1: LLb型
在这里插入图片描述

Case 2: LRb型
在这里插入图片描述

Case 3: RLb型(与LRb型对称)
在这里插入图片描述

Case 4: RRb型与LLb型对称)
在这里插入图片描述

可以观察到,当旋转完成后,新的旋转根全部为黑色,此时不需要再向上回溯进行平衡操作,插入操作完成。需要注意,上面四张图的“叔”、“1”、“2”、“3”结点有可能为黑哨兵结点。

红黑树上结点的删除

STL源码剖析—红黑树原理详解下

第一步:将红黑树当作一颗二叉查找树,将节点删除。

我们先回忆一下前驱节点和后继节点的定义

前驱节点:二叉树中序遍历完成后和这个节点相邻的前面的节点为该节点的前驱节点
后继节点:二叉树中序遍历完成后和这个节点相邻的后面的节点为该节点的后继节点

再看看普通二叉树的节点删除方法:

Z指向需要删除的节点,Y指向实质结构上被删除的结点,

① 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了。即Y指向Z。

② 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。即Y指向Z。

③ 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。即Y指向Z的后继节点。

在这里,后继节点相当于替身,在将后继节点的内容复制给"被删除节点"之后,再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了,下面就考虑后继节点。 在"被删除节点"有两个非空子节点的情况下,它的后继节点不可能是双子非空。既然"的后继节点"不可能双子都非空,就意味着"该节点的后继节点"要么没有儿子,要么只有一个儿子。若没有儿子,则按"情况① "进行处理;若只有一个儿子,则按"情况② "进行处理。

下面是一份在二叉搜索树中删除一个节点的代码示例

/***************************************
* 在BST中删除一个节点
* 先找到要删除的结点,假设为A,A要分三种情况
*  1.A两个子结点为NULL,则直接删除A
*  2.A只有一个非空子结点,
*  3.A有两个子非空结点,
*****************************************/
Node* getMaxOfLeftTree(Node* leftRoot) {if (leftRoot == NULL)return NULL;while (leftRoot->right)leftRoot = leftRoot->right;return leftRoot;
}
Node* getMinOfRightTree(Node* rightRoot) {while (rightRoot->left != NULL)rightRoot = rightRoot->left;return rightRoot;
}Node* deleteNode(Node* root, int key) {if (root == NULL)return NULL;//if (root->data == key)//左子树的最大结点或右子树的最小结点{//情况1if (root->left == NULL && root->right == NULL) {delete root;return NULL;}			//排除情况1后,情况2//只有右结点if (root->left == NULL) {Node* temp = root->right;delete root;return temp;}	//只有左结点if(root->right==NULL) {Node* temp = root->left;delete root;return temp;}//情况3Node* minNode = getMinOfRightTree(root->right);root->data = minNode->data;//很重要,这里是递归删除,为什么不能直接删除这个右子树的最小/左结点//因为这个右子树的最小/左节点可能有一个右结点,所以不能直接删除root->right = deleteNode(root->right, minNode->data);}else if (root->data < key)root->right=deleteNode(root->right, key);else if (root->data > key)root->left=deleteNode(root->left, key);return root;
}

第二步:通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树。

因为"第一步"中删除节点之后,可能会违背红黑树的特性。所以需要通过"旋转和重新着色"来修正该树,使之重新成为一棵红黑树。

再看一下红黑树的几个特性:

(1) 每个节点或者是黑色,或者是红色。
(2) 根节点是黑色。
(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
(4) 如果一个节点是红色的,则它的子节点必须是黑色的。
(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

1.如果Y指向的节点是个红色节点,那么直接删除掉Y以后,红黑性质不会被破坏。操作结束。

2.如果Y指向的节点是个黑色节点,那么就有几条红黑性质可能受到破坏了。
首先是包含Y节点的所有路径,黑高度都减少了一(第5条被破坏)。

其次,如果Y有红色子节点,Y又有红色的父节点,那么Y被删除后,就出现了两个相邻的红色节点(第4条被破坏)。

最后,如果Y指向的是根节点,而Y的子节点又是红色的,那么Y被删除后,根节点就变成红色的了(第2条被破坏)。

其中,第5条被破坏是让我们比较难受的。因为这影响到了全局。这样动作就太大太复杂了。而且在这个条件下,进行其它红黑性质的恢复也很困难。

所以我们首先解决这个问题:如果不改变含Y路径的黑高度,那么树的其它部分的黑高度就必须做出相应的变化来适应它。所以,我们想办法恢复原来含Y节点的路径的黑高度。做法就是:无条件的把Y节点的黑色,推到它的子节点X上去。(X可能是NIL节点)。这样,X就可能具有双重黑色,或同时具有红黑两色,也就是第1条性质被破坏了

但第1条性质是比较容易恢复的:
一、如果X是同时具有红黑两色,那么好办,直接把X涂成黑色,就行了。而且这样把所有问题都解决了。因为将X变为黑色,2、4两条如果有问题的话也会得到恢复,算法结束。

二、如果X是双黑色,那么我们希望把这种情况向上推一直推到根节点(调整树结构和颜色,X的指向新的双黑色节点,X不断向上移动),让根节点具双黑色,这时,直接把X的一层黑色去掉就行了(因为根节点被包含在所有的路径上,所以这样做所有路径同时黑高减少一,不会破坏红黑特征)。
具体可以概括为3种情况。
① 情况说明:x是“红+黑”节点。
处理方法:直接把x设为黑色,结束。此时红黑树性质全部恢复。

② 情况说明:x是“黑+黑”节点,且x是根。
处理方法:什么都不做,结束。此时红黑树性质全部恢复。

③ 情况说明:x是“黑+黑”节点,且x不是根。

在③的情况下,X节点是双层黑色,且X有父节点P(X不是根,所以必定有父亲)。同时,X必然有兄弟节点W,而且这个W节点必定有两个子节点。(因为这是原树满足红黑条件要求而自然具备的。X为双黑色,那么P的另一个子节点以下一定要有至少两层的节点,否则黑色高度不可能和X路径一致)
所以我们就分析这些节点之间如何变形,把问题限制在比较小的范围内解决。

另一个前提是:X在一开始,肯定是树底的叶节点或是NIL节点,所以在递归向上的过程中,每一步都保证下一步进行时,至少 X的子树是满足红黑特性的。
因此子树的情况就可以认为是已经正确的了,

这样,分析就只限制在X节点,X的父节点P和X的兄弟节点W,以及W的两个子节点。这些个节点中

在X具有双重黑色的情况下,算法的过程就是将这多出的一重黑色向上移动,直到遇到红节点或者根节点。

接着往下分析, 会遇到4种情况,实际上是8种, 因为其中4种是相互对称的,这可以通过判断X是其父节点的右孩子还是左孩子来区分。

下面我们以X是其父节点的左孩子的情况来分析这4种情况,实际上接下来的调整过程,就是要想方设法将经过X的所有路径上的黑色节点个数增加1

具体分为以下四种情况:(下面针对x是左儿子的情况讨论,右儿子对称)

Case1:X的兄弟W是红色(想办法将其变为黑色)
由于W是红色的,因此其儿子节点和父节点必为黑色,只要将W和其父节点的颜色对换,在对父节点进行一次左旋转,便将W的左子节点放到了X的兄弟节点上,X的兄弟节点变成了黑色,且红黑性质不变。但还不算完,只是暂时将情况1转变成了下面的情况2或3或4。

在这里插入图片描述

Case2:X的兄弟节点W是黑色的,而且W的两个子节点都是黑色的,此时可以将X的一重黑色和W的黑色同时去掉,而转加给他们的父节点上,这时X就指向它的父节点了,因此此时父节点具有双重颜色了。这一重黑色节点上移。
在这里插入图片描述
如果父节点原来是红色的,现在又加一层黑色,那么X现在指向的这个节点就是红+黑两色的,直接把X(也就是父节点)着为黑色。问题就已经完整解决了。

如果父节点现在是双层黑色,那就以父节点为新的X进行向上的下一次的递归。

Case3:X的兄弟节点W是黑色的,而且W的左子节点是红色的,右子节点是黑色的
此时通过交换W和其左子节点的颜色并进行一次向右旋转就可转换成下面的第四种情况。注意,原来L是红色的,所以L的子节点一定是黑色的,所以旋转中L节点的一个子树挂到之后着色为红色的W节点上不会破坏红黑性质。变形后黑色高度不变。

在这里插入图片描述
Case4:X的兄弟节点W是黑色的,而且W的右子节点是红色的。
这种情况下,做一次左旋,W就处于X父亲A的位置,将W保持为原来的A的位置的颜色,同时将W的两个新的儿子节点的颜色变为黑色,去掉X的一重黑色。这样整个问题也就得到了解决。递归结束。(在代码上,为了标识递归结束,我们把X指向根节点)

在这里插入图片描述
因此,只要按上面四种情况一直递归处理下去,X最终总会指向根结点或一个红色结点,这时我们就可以结束递归并把问题解决了。

4种情况总结如下表

现象说明处理策略
Case 1X是"黑+黑"节点,X的兄弟节点W是红色。(01) 将X的兄弟节点W设为“黑色”。
(此时X的父节点和X的兄弟节点W的子节点都是黑节点)(02) 将X的父节点设为“红色”。
(03) 对X的父节点进行左旋
(04) 左旋后,重新设置X的兄弟节点W
Case 2x是“黑+黑”节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色(01) 将X的一重黑色和其兄弟节点W的黑色同时去掉,而转加给他们的父节点上,此时父节点具有双重颜色了
(02) 设置“X的父节点”为“新的X节点”。
Case 3X是“黑+黑”节点,X的兄弟节点W是黑色;X的兄弟节点W的左孩子是红色,右孩子是黑色的。(01) 将X兄弟节点W的左孩子设为“黑色”。
(02) 将X兄弟节点W设为“红色”。
(03) 对X的兄弟节点W进行右旋。
(04) 右旋后,重新设置X的兄弟节点W。
Case 4X是“黑+黑”节点,x的兄弟节点W是黑色;X的兄弟节点W的右孩子是红色的,X的兄弟节点W的左孩子任意颜色。(01) 将X父节点颜色赋值给X的兄弟节点W(即,将W保持为原来X的父亲的颜色)。
(02) 将X父节点设为“黑色”。
(03) 将X兄弟节点W的右子节设为“黑色”。
(04) 对X的父节点进行左旋。
(05) 设置“X”为“根节点”(这里是为了标识递归结束)。

代码就不贴了,具体的可以看看上面的几篇参考博文。


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

相关文章

红黑树原理

因为看的时候写在了纸上&#xff0c;于是直接扫描的&#xff0c;效果不太好。

HashMap红黑树原理解析

HashMap红黑树原理解析 定义&#xff1a; 简单来说红黑树是一种近视平衡二叉查找树&#xff0c;主要优点是”平衡”&#xff0c;即左右子树高度几乎一致&#xff0c;以此来防止树退化为链表&#xff0c;通过这种方式来保障查找的时间复杂度为log(n)。 下面先主要提一下红黑树…

红黑树的原理及实现

红黑树的原理及实现 一、什么是红黑树二、定义红黑树三、左旋和右旋四、红黑树插入节点 一、什么是红黑树 红黑树是一种特定类型的二叉树&#xff0c;它是在计算机科学中用来组织数据比如数字的块的一种结构。 红黑树是一种平衡二叉查找树的变体&#xff0c;它的左右子树高差有…

【图文详解】彻底了解红黑树底层实现原理

红黑树定义 红黑树&#xff08;Red Black Tree&#xff09; 是一种自平衡二叉查找树&#xff0c;是在计算机科学中用到的一种数据结构&#xff0c;典型的用途是实现关联数组。 红黑树是一种特化的AVL树&#xff08;平衡二叉树&#xff09;&#xff0c;都是在进行插入和删除操…

红黑树(一)之 原理和算法详细介绍

概要 目录1 红黑树的介绍2 红黑树的应用3 红黑树的时间复杂度和相关证明4 红黑树的基本操作(一) 左旋和右旋5 红黑树的基本操作(二) 添加6 红黑树的基本操作(三) 删除 作者&#xff1a;Sky Wang 于 2013-08-08 概述&#xff1a;R-B Tree&#xff…

数据结构 | 【红黑树】图解原理

今天我们要说的红黑树就是就是一棵非严格均衡的二叉树&#xff0c;均衡二叉树又是在二叉搜索树的基础上增加了自动维持平衡的性质&#xff0c;插入、搜索、删除的效率都比较高。红黑树也是实现 TreeMap 存储结构的基石。 红黑树就是非严格均衡的二叉搜索树。 一、红黑树规则特…

红黑树原理简单解析

一、红黑树为什么会出现呢&#xff1f; 是因为二叉搜索树有可能会出现极端的情况&#xff0c;就是只有一侧有数据&#xff0c;那这样的话就会降级为链表。后来出现了平衡二叉树&#xff0c;但是由于强制平衡所导致付出的代价比较高昂&#xff0c;所以黑红树出现了。 二、简介…

laravel框架的下载与安装

首先我们先访问这个网址https://github.com/laravel/laravel 可以使用git克隆 或者直接下载安装包到自己的www目录下解压&#xff0c;此时访问localhost下的laravel目录&#xff0c; 此时会报没有vendor文件夹的一个错&#xff0c; 如果你已经下载了composer 在该文件夹目录下…

Laravel

Laravel的安装 1.确认composer已经安装 2.配置homestead.yaml文件sites&#xff1a;- map: laravel.xyz//域名配置to: /home/vagrant/code/laravel/public//入口文件路径 databases&#xff1a;//数据库- laravel 3.用秘钥登录homestead 4.更换中国镜像&#xff1a; composer…

Laravel下载文件及文档

2019独角兽企业重金招聘Python工程师标准>>> Laravel学院提供的相关资源下载 中文文档 Laravel 5.6 中文文档&#xff1a;PDF&#xff08;兼容 5.5 文档&#xff09; Laravel 5.3 中文文档&#xff1a;CHM | PDF Laravel 5.2 中文文档&#xff1a;CHM | PDF Laravel…

Laravel-admin的安装步骤

1、先确保是否安装composer&#xff0c;laravel及其版本并切换到阿里镜像 composer -v 查看composer的版本 php artisan 查看laravel的版本 扩展说明下&#xff1a;如果已经安装好composer&#xff0c;也可以通过 Composer 安装 Laravel 安装器 命令如下&#xff1a;composer…

如何正确的下载安装使用别人的laravel项目?

转载的,写的很简洁明了,白俊瑶博客 laravel 作为最流行的 php 框架&#xff1b;自然少不了很多基于 laravel 开发的项目&#xff1b;不过很多项目因为还处于开发中&#xff1b;或者其他原因并没有写安装文档&#xff1b;举个反面栗子&#xff1b;比如说我的 laravel-bjyadmin ;…

laravel 5.0

1.应用场景 使用PHP5.4[因为php5.4只能最高支持laravel 5.0]快速开发/维护一个web系统 2.学习/操作 1.获取参数 get方式 【查询字符串方式&#xff1a;Query String】 http://test.oa.com/api/u2d/texture/export?nametest&sex男 Route::get(export, U2dTextureControll…

Laravel最新版的安装(图文)

本文只适合刚接触或者想学Laravel的小白&#xff0c;老鸟就自动略过吧。 Laravel是一套简洁、优雅的PHP WEB开发框架&#xff08;PHP Web Framework&#xff09;&#xff0c;具有富于表达性且简洁的语法&#xff0c;Laravel是易于理解且强大的&#xff0c;它提供了强大的工具用…

Laravel 安装

工作需要&#xff0c;得学习一个php的后台admin管理框架&#xff0c;用于管理内容。这一天都在搜GitHub和gitee&#xff0c;GitHub是真的难访问啊&#xff0c;时断时续的&#xff1b;gitee上有一些&#xff0c;但好多都停更了的样子&#xff0c;有一些还不错的&#xff0c;例如…

Laravel 8 文件的上传/下载/显示的实例

如何实现对文件的操作&#xff0c;实现上传&#xff0c;下载&#xff0c;展示等等功能&#xff0c;我们通过编写一个简单的实例来了解其中具体的内容。 文件列表的展示/文件上传/文件下载 首先我们需要创建两个文件&#xff0c;一个视图文件&#xff0c;一个控制器&#xff0c…

安装laravel

安装laravel之前首先应该设置好安装好php&#xff0c;配置好环境变量。之后安装好compser。 1、安装php环境变量。 我使用的php环境安装包是upupw&#xff0c;&#xff08;php环境安装包有很多&#xff0c;例如phpstudy&#xff0c;wamp等等&#xff0c;读者可自行百度。&…

Laravel框架 -- 文件下载功能

Laravel 文件下载功能&#xff0c;通过手册&#xff0c;我们可以发现&#xff0c;Response的download方法就是我们所需要的文件下载功能的重要元素。 首先&#xff0c;我们注意一下&#xff0c;上面的方法中有两种写法&#xff0c;那么我以第二种为例子&#xff0c;解释一下实际…

laravel安装

文章目录 前言一、下载composer二、安装composercmd 输入composer 检验 三、配置镜像第一步第二步 四、虚拟目录配置 前言 前提&#xff1a;安装了phpStudy套件。https://www.xp.cn/download.html 一、下载composer 从laravel5.x 开始 , 官网https://getcomposer.org/Compose…

laravel文件上传与下载

https://github.com/Chumper/Zippergithub地址 composer require chumper/zipper看到这个代表安装成功 代表路由 . . . // package chumper/zipper Route::get(zip, ZipControllerindex)->name(zip.index); Route::post(zip/download, ZipControllerdownload)->name(zi…