美文网首页
数据结构&算法之《红黑树》

数据结构&算法之《红黑树》

作者: 忧郁的小码仔 | 来源:发表于2019-08-25 16:36 被阅读0次

为什么会有红黑树?


二叉搜索树是一个很不错的数据结构,正常情况下可以很快速的查找,删除和添加元素,但是在某些情况下它会变得很糟糕,比如,插入的元素是有序的,那么二叉搜索树就变成了只有左子树或者只有右子树的怪物,实际上就变成了链表结构,像这种平衡度很差的搜索二叉树的执行效率就变得很差。

为了能高效的搜索一颗二叉搜索树,就要保证树本身是平衡的(或者大致平衡),这里的平衡说的是树的左边的后代数目和右边的后代数目大致相同。而我们要说的红黑树就是这样的平衡二叉树。

对于每一个要插入的节点,红黑树的插入程序都会检查会不会破坏树的特征结构,如果结构被破坏了,程序就会修正,根据需要改变树的结构,来保证树的平衡。

红黑树的特质


1.红黑树的每个节点不是红色就是黑色(其实就是一个标志位而已)
2.根节点一定是黑色的
3.如果节点是红色的,那么它的子节点必须是黑色的, 反之则不一定
4.从根节点到叶子节点的每条路径上,必须包含相同数目的黑色节点

为什么插入的节点总是红色的?


在红黑树中新插入的节点总是红色的,这不是随随便便拍大腿决定的;因为插入黑色节点一定会违背红黑树特质[4](因为一条路径上多了一个黑色节点),而插入红色节点则只有一半的机会违背红黑树特质[3] (如果新节点的父节点是红色,就违背了特质[3]),并且先人们说了,违背特质[3]比违背特质[4]更容易修正。

节点之间的关系

在开始下面的内容之前,我们要先明白节点和节点之间的关系,因为后面的内容中会用到这些关系术语,这里,我们用一张图来表示:


节点关系图

这里,以节点[12]为例子,它的一些长辈和晚辈如下:
1.左孩子和右孩子: [11][13]
2.兄弟: [18]
3.近侄子: [16]; 远侄子: [19]; 这里的远近相信大家能判断出来。比如[18]的近侄子就是[13],远侄子就是[11]
4.父亲: [14]
5.叔叔: [2]
6.祖父: [10]

红黑树的平衡性修正


红黑树平衡性修正的方法只有三种:变色、左旋和右旋

1.变色
变色很简单,其实主要是新插入的红色节点的父节点是红色节点(违背了红色节点的子节点必须是黑色节点的特质),只需要修改父节点的颜色即可

2.左旋 && 右旋
例如,有这样一棵树,我们以节点[2]为支点进行左旋:

左旋
过程是这样的:1.将节点[7]的左孩子[5]转接到节点[2]的右孩子上;2.将节点[2]的父节点[11]变成节点[7]的父节点;3. 将节点[2]转接到节点[7]的左孩子上

右旋则正好相反,比如:以节点[7]为支点进行右旋:

右旋
过程是这样的:1.将节点[2]的右节点[5]转接到节点[7]的左孩子上;2.将节点[7]的父节点[11]变成节点[2]的父节点;3.将节点[7]转接到节点[2]的右孩子上。

这里对红黑树进行左旋和右旋的原因,主要是为了调整红黑树的平衡度

红-黑树的插入图解


红黑树的插入可以分解为这么几个步骤:

1: 插入的是第一个节点,直接设为根节点,变成黑色即可,不需要修正
2: 插入节点的父节点是黑色的(因为插入的红色节点不违背每条路径上黑色节点数相同这一特质),不需要修正
3: 插入节点的父节点是红色;(因为插入的红色节点违背了红色节点下必须是黑色节点这一特质),所以这种情况都需要修正
3.1:叔叔节点是红色;修正过程如下:
    1. 将父节点和叔叔节点变黑
    2.将祖父节点变红 *
    3.将祖父节点设为当前节点,然后对新的当前节点重新修正
3.2:叔叔节点是黑色;又分下面几种情况
    3.2.1:当前节点是父亲的左孩子,父亲是祖父的左孩子;修正过程如下:
      
1.以祖父为支点右旋 *
      2.交换父亲和祖父的颜色
    3.2.2: 当前节点是父亲的右孩子,父亲是祖父的左孩子;修正过程如下:
      1.以父亲为支点左旋 *
      
2.将父亲设为当前节点重新修正*
    3.2.3: 当前节点是父亲的右孩子,父亲是祖父的右孩子;修正过程如下:
      1.以祖父为支点左旋 *
      
2.交换父亲和祖父的颜色*
    3.2.4: 当前节点是父亲的左孩子,父亲是祖父的右孩子
      1.以父亲为支点右旋 *
      
2.将父亲设为当前节点重新修正*

下面我们用图形来展示下插入的修正过程:


插入修正过程

这里展示了绝大部分的情况,只要按照每种情况下的修正原则来修正就可以了。

红黑树的删除图解


删除节点这里要分两部分来处理

1. 节点交换

如果直接将节点在原位置删除的话,需要考虑删除节点的左右子树的嫁接问题,有点麻烦;另外一种方法是将要删除的节点和它的最小后继或者最大前继交换,然后再删除,本章节中,我们采用交换最小后继的方式,比如,下面这样:


交换最小后继

注意,这里交换的只是节点的值,不要交换节点的颜色;另外,交换的话还有几种情况,我们要把要删除的节点一直交换到叶子节点为止,所以要循环去交换直到完成。

情况1. 当前节点没有孩子,是叶子节点
   1. 节点是红色的,直接删除即可
   2. 节点是黑色的,删除后违背红黑树特质,需要做后面的变色旋转修正处理,然后再删除
情况2. 当前节点有两个孩子节点;
   则从后继节点中找到最小后继D, 交换当前节点和节点D的值,然后把原节点D作为当前节点重新走交换节点流程
情况3. 当前节点只有左孩子L;
   交换当前节点和L节点的值,然后把原L节点作为当前节点重新走交换节点流程
情况4. 当前节点只有右孩子R;
   交换当前节点和R节点的值,让后把原R节点作为当前节点重新走交换节点流程

经过上面的处理,我们就把要删除的节点移位到了叶子节点;剩下要做的就是处理情况1中的第2种情况中的变色旋转

2. 变色旋转

为了后续方便,我们用下面的简称来代表节点之间的关系 (节点之间的关系我们在上面已经描述过了,不记得的可以往上翻一翻):
P: 当前节点的父节点
W: 当前节点的兄弟节点
Nf: 当前节点的远侄子
Nn: 当前节点的近侄子

情况1:当前节点是根节点或者是红色节点
   直接将其变成黑色,变色旋转结束;
情况2:W是红色
   则将W设为黑色,P设为红色,对P进行旋转(当前节点是P的左节点时,左旋,当前节点是P的右节点时右旋);然后再重新进行旋转变色
情况3:W是黑色,且它的两个孩子也是黑色
   则将w设为红色,将P设为当前节点,重新进行旋转变色
情况4:W是黑色,Nf是红色
   则将W设为P的颜色,P和Nf设为黑色,并对P进行旋转(当前节点是P的左孩子就左旋,是右孩子就右旋),变色旋转结束;
情况4:W是黑色,Nf是黑色
   则交换W和Nn的颜色,并对W进行旋转(当前节点是P的左孩子则右旋,是右孩子则左旋),然后重新进行旋转变色;

下面是一个删除示例:


删除图示

具体的代码实现

iOS demo


自从工作之后,感觉算法用到的场景很少,大部分都是底层用的比较多,实际业务中用的比较少,导致一些基本的数据结构和算法都忘记了,再者由于现在面试中都喜欢面试数据结构和算法,也算是未雨绸缪吧,接下来准备把常用的基本数据结构和算法全都重新复习一遍。

最后,感谢几位大神的文章解惑:
【数据结构和算法05】 红-黑树
红黑树原理以及插入、删除算法 附图例说明

相关文章

  • (313)红黑树-java实现

    引言 根据《算法》第4版。编写红黑树。 理论 参见: 浅谈算法和数据结构: 八 平衡查找树之2-3树 浅谈算法和数...

  • 数据结构与算法之美-25讲红黑树(上)

    数据结构与算法之美-25讲红黑树(上) 特别备注 本系列非原创,文章原文摘自极客时间-数据结构算法之美[https...

  • 数据结构与算法之美-26讲红黑树(下)

    数据结构与算法之美-26讲红黑树(下) 特别备注 本系列非原创,文章原文摘自极客时间-数据结构算法之美[https...

  • 数据结构 - 红黑树

    更多数据结构内容,请参考:数据结构 - 概要 简介 红黑树介绍请参考: 漫画:什么是红黑树? 面试旧敌之红黑树 红...

  • 红黑树笔记

    红黑树:R-B Tree [toc]参考:红黑树(一)之 原理和算法详细介绍红黑树(五)之 Java的实现 1 简...

  • 数据结构红黑树添加、修改原理分析

    源码分析大纲 数据结构解析 红黑树试下原理刨析 数据结构解析 1.红黑树 1.1 红黑树概念 红黑树(Red Bl...

  • 数据结构与算法-AVL 红黑树

    AVL树AVL树 算法红黑树红黑树 B站

  • 数据结构&算法之《红黑树》

    为什么会有红黑树? 二叉搜索树是一个很不错的数据结构,正常情况下可以很快速的查找,删除和添加元素,但是在某些情况下...

  • 数据结构算法之红黑树

    红黑树的特性 (1)每个节点要么是黑色,要么是红色。(2)根节点是黑色。(3)每个叶子节点(NIL)是黑色。 [注...

  • 无标题文章

    ## 知识点 1. 算法 基本的排序算法,时间复杂度 2. 数据结构 链表,查找,插入;平衡二插树,红黑树 2. ...

网友评论

      本文标题:数据结构&算法之《红黑树》

      本文链接:https://www.haomeiwen.com/subject/tvxkectx.html