【数据结构】红黑树详解

1  前言

数据结构很基础也很重要,它重要在哪呢,当然当你的数据量比较比如就很小几十几百的,你随便用什么数据结构,当你的数据量比较大的时候,这个时候对数据操作的效率每种数据结构的特长点就会慢慢出现差异,所以我们要对数据结构有一定的认知,我们才能更好的使用相适应的数据结构来加速我们的代码,是不是,那么这节我们就来看下一种典型的数据结构-红黑树。

附在线红黑树,方便大家边看边尝试:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

先统一一下叫法哈:

其它:我的图里都没画叶子节点哈,叶子节点大家可以都看作是NULL节点哈,当黑节点来看哈。

2  红黑树简介

红黑树也是一种树型结构,一种二叉排序树,我们知道二叉树有很多变种,二叉排序树、完全二叉树、满二叉树、AVL树等等,树之所以有这么多变种,就是因为规则不同,约束不同而形成的各式各样,红黑树也是如此。

2.1  红黑树的由来

那我们要先来看下早期的二叉排序树:对于任意一个结点,其左子树的值必定小于该结点,其右子树的值必定大于该结点。那么中序遍历的时候,就是有序的了。理论上来说,增加,删除,修改的时间复杂度都是O(log(N))。但是它存在一个致命的问题。 就是如下图,很容易链化,导致增加,删除,修改的时间复杂度退化为O(N) 

那么后续出现了AVL树,也就是平衡二叉树:它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉搜索树。如果向树中插入[1,2,3,4,5] 

可以看到AVLTree在最坏的情况下,依然保持了“绝对的平衡”:左右两个子树的高度差的绝对值不超过1。那么AVL Tree是如何保证平衡的呢,是通过旋转,可以看到,无论是插入还是删除元素,都要去通过旋转维护整个树的平衡。

  • AVL查询元素:O(log(N)) 
  • AVL插入元素:最多一次旋转O(1),加上查询的时间O(log(N)),插入的复杂度O(log(N)) 
  • AVL删除元素:必须检查从删除结点开始到根结点路径上的所有结点的平衡因子。因此删除的代价比较大,删除最多需要log(N)次旋转,加上查询的时间,删除的复杂度O(2log(N)) 

我们发现,AVL树未免太严格了一些,有没有一种数据结构,能让AVL树不那么严格平衡,降低维护平衡的开销,同时又不能像二叉排序树一样退化呢?就引出了我们的红黑树,它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的红黑树

  • 查询元素:O(log(N)) 
  • 插入元素:插入最多2次旋转,加上查询的时间O(log(N)),插入的复杂度O(log(N)) 
  • 删除元素:删除最多需要3次旋转,加上查询的时间,删除的复杂度O(log(N)) 

可以看到红黑树具有良好的效率,它可在 O(logN) 时间内完成查找、增加、删除等操作。因此,红黑树在业界应用很广泛,比如 Java 中的 TreeMap,JDK 1.8 中的 HashMap、C++ STL 中的 map 均是基于红黑树结构实现的。

2.2  红黑树的性质

红黑树大概有6条性质也就是约束,我们来看下:

  • (1)每个节点不是红就是黑 (这个好理解的吧 所以它才叫红黑树)
  • (2)根节点是黑的(根黑)              
  • (3)所有叶子节点都是黑色(这里的叶子结点指的是为null的结点) 
  • (4)每个红色节点必须有两个黑色的子节点(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  • (5)从任一节点到叶子节点,所包含的黑色节点数目相同(即黑高度相同) 
  • (6)最长路径长度不超过最短路径长度的2倍(一条黑红黑红…一条全黑)

前3条约束应该好理解吧,都是基础信息约束,后面就是对行为工作约束,来避免二叉排序树退化成单链表的情况。性质6其实可以由性质4、5推出来:每条路径上黑色节点数量相等,并且红色节点不能连续,假设每条路径上黑色结点的数量是n,那么最短路径上结点数是n,最长路径上结点数是2*n(每个红色结点都插在黑色节点之间,保证红色节点不连续),这样就保证最长路径不超过最短路径的两倍。

到叶子节点的路径上的节点全是黑色,那么这条路径就是最短路径,这个大家理解么,性质5说黑色节点相同,而性质4红节点下必有俩黑,那么是不是都黑的情况下,就是最短的路径呢?是的吧。我们再用反证法的思想证明下:

我们要证明的:如果一棵红黑树存在一条从根节点出发仅包含黑色节点的路径,那么该路径必为该红黑树的最短路径之一。

反证法:如果一棵红黑树中已存在一条从根节点出发仅包含黑色节点的路径 P1,节点数记为 m。假设命题为假,则存在任一从根节点出发包含至少 1 个红色节点的路径 P2,该路径比 P1 更短。P2的节点数记为 n,由于 P2 比 P1 更短,因此可推出 n < m。

根据红黑树的性质5:从任一个节点到其外部节点的所有路径包含相同数量的黑色节点。那么从根节点出发,P1 和 P2的黑色节点数均为 m。由于 P2 至少还有 1 个红色节点,因此 P2 中包含的节点数 n >= m + 1 ,即 n > m,这与 n < m 的假设相矛盾,假设不成立。因此,原命题成立。

所以当存在一条全黑路径的话,它一定是最短路径,当然不一定所有的红黑树都一定存在全黑路径吧,是不是。

还有一条比较重要的隐含性质:任意一个以黑色节点为根的子树也必定是一颗红黑树。

3  红黑树操作

红黑树的基本操作和其他树形结构一样,一般都包括查找、插入、删除等操作。我们接下来看看。

3.1  红黑树旋转

在分析插入和删除操作前,我们需要先说明一下旋转操作,这个操作在后续操作中都会用得到。旋转操作分为左旋和右旋,左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子。

3.1.1  左旋示例

3.1.2  右旋示例

3.2  插入

红黑树的插入过程和二叉查找树插入过程基本类似,不同的地方在于,红黑树插入新节点后,需要进行调整,以满足红黑树的性质。性质1规定红黑树节点的颜色要么是红色要么是黑色,那么在插入新节点时,这个节点应该是红色还是黑色呢?

我都想不说答案,大家直接看性质5,你插个黑的是不是必然会影响是不是就要调整了,是不是必然就是红的了,对的吧,红的出现两红连续了,可能才需要调整,对的吧,所以插入的节点应该是红色的。

插入我们可能感觉很迷茫,不知道如何下手,这玩意这可咋插入呀,一想到就头大就逃避,哈哈哈,凡复杂事情,其实按情况去划分,把每种情况都克服了,整体也就克服了。我们站在待插入节点的角度,去看我要往哪个父节点下插入,那么看父节点的话,那插入的几种情况我们就来看看哈,我们这里待插入的节点为N节点:

3.2.1  情况一:父节点为空

当父节点为空,也就是到根节点了,因为性质2所以将节点 N 直接变黑作为根节点,即可。

3.2.2  情况二:父节点是黑色

当父节点是黑色,这种情况下,性质4和性质5没有受到影响,不需要调整。

3.2.3  情况三:父节点是红色,叔叔也为红色。

待插入节点N的父节点为红色,叔叔也是红色的情况时,性质4就会被打破,此时需要进行调整。这种情况下,先将 父节点 和 叔叔节点 染成黑色,再将 爷爷节点 的颜色染成红色。此时经过爷爷的路径上的黑色节点数量不变(想想是不是),性质5仍然满足。但需要注意的是 G 被染成红色后,可能会和它的父节点形成连续的红色节点,此时需要递归向上调整

当然此情况下的这些情况都属于情况三哈。

3.2.4  情况四:父节点是红色,叔叔为黑色。

这种情况跟情况三的不同关键点就在于叔叔的节点颜色,情况三叔叔是红色,而情况四叔叔是黑色的哈。我们的角度从父节点的左右以及待插入节点是父节点的左右可以分成细拆成4种情况,我们来看下这四种情况的处理:

(1)父节点为左子树,待插入节点为父节点的左子树

(2)父节点为左子树,待插入节点为父节点的右子树

小记:当父节点为左子树时,待插入的节点都要往左靠(这个理解不,你看上图待插入N在父节点P的右边时,是不是先左旋了一下,都靠左边了,然后跟待插入节点在左子树时保持都靠左边啦)然后父节点和爷爷换色,然后右旋的。

(3)父节点为右子树,待插入节点为父节点的右子树

(4)父节点为右子树,待插入节点为父节点的左子树

小记:可以看到跟左子树的思路其实差不多,先把节点都往右靠,只是旋转方向不一样,右子树是左旋,左子树是右旋。

3.2.5  插入小结

针对插入我们看到,划分情况来处理哈:

  • 父节点为空的话,就直接变黑即可
  • 父节点为黑的话,保持位置不变即可
  • 父节点为红的话,就要观察叔叔节点的颜色
  • 父节点为红,叔叔为红,直接父亲和叔叔变黑,爷爷变红,然后以爷爷为中心继续递归处理
  • 父节点为红,叔叔为黑,就要父亲是左子树还是右子树以及待插入的是父亲的左子树还是右子树,父亲是左子树就要往左靠,所以待插入如果在父亲的右子树就要先左旋,然后父亲和爷爷换色,然后以爷爷为中心右旋哈,
  • 父节点为红,叔叔为黑,父亲是右子树就要往右靠,所以待插入如果在父亲的左子树就要先右旋,然后父亲和爷爷换色,然后以爷爷为中心左旋哈。

3.3  删除

相较于插入操作,红黑树的删除操作则要更为复杂一些。删除操作首先要确定待删除节点有几个孩子,如果有孩子,不能直接删除该节点。我们看上边插入的时候看的是叔叔节点的眼色,而删除是看的待删除节点的兄弟节点的颜色。还是一样我们站在待删除节点的角度,我们可以从如下两个方面去考虑:

  • 节点的颜色,节点有红黑两种可能,那么删除黑节点就会造成节点失衡。
  • 节点的构造,有三种可能:其一是删除节点的孩子都为null,其二是删除节点的一个孩子节点为null,其三是删除节点的两个孩子节点都不为null。而如果两个节点都不为null,那么我们就需要找替代节点(前驱或者后继结点)来替代删除,而删除替代结点就会是情况一和情况二。

删除的第三种情况大家应该知道吧,跟我们二叉排序树删除是不是要找一个前驱或者后继节点来替换,然后将前驱或者后继节点的值赋值给待删除的节点,然后删除前驱或者后继节点。而前驱或者后继结点的判断可以使用下图的方式,将节点Key落入X轴中(实质是中序排序)其后一个结点就是后继节点,前一个就是前驱节点,那么我们看一下后继节点替代删除的方案,比如删除-1,那么可以将0替换到-1的位置,然后删除0,这样就回到情况一, 再比如删除4,那么使用5来代替,然后删除5,这样就回到了情况二。

由于前驱和后继至多只有一个孩子节点,这样我们就把原来要删除的节点有两个孩子的问题转化为只有一个孩子节点的问题,问题被简化了一些。这个大家理解的吧,不理解的话建议大家先去看一下二叉排序树的东西,比如二叉排序树的删除,再来这里看红黑树就好理解一点了。

那么针对红黑树的删除,我们这里可分为三种情形:

  • 删除的节点有一个孩子节点,删除节点只能是黑色,其子节点也必为红色,此时用删除节点的子节点接到父节点,且将子节点颜色涂黑,保证黑色数量。

  • 删除的节点没有孩子节点,如果是红色还好直接删除即可,如果是黑色就需要考虑平衡了

     

  • 删除的节点有两个孩子节点,与二叉排序树一样,使用前驱或者后继节点作为替换的删除节点,场景转至为1或2处理。

接下来我们就仔细分析下情形一和情形二。

3.3.1  删除节点仅存在一个孩子

删除节点存在一个孩子,那么此时,不需要考虑节点的颜色,因为该节点必然为黑色 (因为性质4,红下必有俩黑或者俩null节点,而我们这里的情况是只有一个孩子,所以必为黑),且孩子节点必然为红(如果为黑,那么D节点就会有一方黑色节点比另一方多一,这个理解么?因为我们说过红黑树的任一黑节点为根的树也必是一颗红黑树)。那么情况一的所有情况如下:

这种情况处理较为简单,只需要将节点P的指针指向DL或者DR,然后将DL或者DR的颜色变更为黑色, 就保证了红黑树的平衡,如下:

上述情况需要注意当D是根节点时,删除操作之后,孩子节点会成为新的根节点

3.3.2  删除节点不存在孩子

删除节点不存在孩子,那么此时就需要考虑节点的颜色。

3.3.2.1  删除节点为红色

如果为红色,因为性质4那么父节点肯定为黑色,那么直接删除即可哈,P节点断掉指向节点D的指针指向就好了。

3.3.2.2  删除节点为黑色

我们考虑黑色,这种情况较为复杂,因为黑色节点被删除之后,红黑树会失去平衡,此时需要调整平衡。那么可能的情况有如下几种(如果D为根节点,删除操作后,红黑树变为空树即可,下面以非根节点的情况为例来分析)

3.3.2.2.1  父节点为红色,兄弟节点不存在孩子

父节点为红色,兄弟节点不存在孩子(兄弟节点必然存在,且为黑色),这种情况稍微好处理,因为将父节点变为黑色,兄弟节点变为红色,即可保证红黑树平衡。

3.3.2.2.2  父节点为红色,兄弟节点存在孩子

父节点为红色,兄弟节点存在孩子,此时无法像情况 3.3.2.1 那么处理,因为兄弟节点存在的孩子必然为红色(理解么?因为我们说了要删除的节点D没有孩子,父亲是红,兄弟就必是黑节点,黑节点下如果还有黑节点,是不是父节点为根的子树就不是红黑树了,对不对),那么此时就需要进行旋转。

3.3.2.2.3  父节点为黑色

当兄弟结点不存在孩子节点,此时无法通过旋转来实现平衡,即P节点无法继续调整,那么就B设置为 红色,保证P这个子树平衡,然后通过P节点,向上递归维持平衡。

比如P的父亲是红色的话:

3.3.3  删除小结

(1)删除节点之后,看看这个节点是不是黑色的叶子节点,如果不是,简单处理就可以达到平衡了;

(2)先看N是不是根节点,是的话啥都不用管;不是的话看兄弟什么颜色:

  兄弟是红色:进行旋转涂色,去到兄弟为黑色那里处理

  兄弟是黑色,看看兄弟子节点是不是全部都是黑。

    全黑的话,看父节点什么颜色进行对应处理;

         不全黑,看兄在的位置,兄在左的话,看兄的左子是不是红色,进行对应处理;兄在右的话,看兄的右子是不是红色,进行对应处理。

4  小结

红黑树到这里就差不多了,基于二叉排序树加上自己的约束形成一棵红黑树,查询跟二叉排序树的查找类似,插入和删除的话就需要考虑节点颜色以及是否违反约束进行相应的变色和旋转,还是需要动手实际操作的哈,边看边理解,有理解不对的地方欢迎指正哈。

posted @ 2023-04-29 17:05  酷酷-  阅读(118)  评论(0编辑  收藏  举报