0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

红黑树

修罗 2021-11-27 1332 0条评论 js数据结构

首页 / 正文

一. 前言:

1.1 二叉搜索树的缺陷:

如果插入一连串连续的数据,如下图所示:

1637978105674.png

形成了一颗非平衡树:

  • 比较好的二叉搜索树应该是左右分布均匀的;
  • 但是插入连续数据后,分布的不均匀,变成非平衡树;
  • 对于一颗平衡二叉树来说,插入或查找等的操作效率是O(logN);
  • 对于一颗非平衡二叉树,相当于编写了一个链表,查找效率变成了O(N);

1.2 常见的平衡树

为了能以较快的时间O(logN)来操作一棵树,我们需要保证树尽量是平衡的,时间复杂度接近O(logN);

常见的平衡树有哪些呢?

AVL树

  • AVL树是最早的一种平衡树,它有办法保持树的平衡(每个节点多存储了一个额外的数据);
  • 因为AVL树是平衡的,所以时间复杂度也是O(logN);
  • 但是,每次插入或删除操作相对于红黑树来说都不高,整体效率不如红黑树;

红黑树

  • 红黑树也通过一些特性来保持树的平衡;
  • 因为是平衡树,所以时间复杂度也是O(logN);
  • 每次插入或删除操作,红黑树性能优于AVL树,所以现在平衡树的应用基本都是红黑树。

二. 认识红黑树

2.1 邂逅红黑树

首先,红黑树很难,难到什么程度呢?

  • 数据结构中一个难点中的难点;
  • 数据结构很难,红黑树将难度上升了一个档次;

ok,在这里,一起来踏入数据结构红黑树这块禁区。

2.2 红黑树的规则

红黑树除了符合二叉搜索树的基本规则外,还添加了以下特性:

  1. 节点是黑色或红色;
  2. 根节点是黑色;
  3. 每个叶子节点都是黑色的空节点(NIL节点);
  4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

1637979903498.png

2.3 红黑树的相对平衡

前面的约束,确保了红黑树的关键特性:

  • 从根叶子的最长路径,不会超过最短可能路径的两倍长;
  • 结果就是这个树基本是平衡的;
  • 虽然没有做到绝对的平衡,但是可以保证在最坏的情况下,依然是高效的;

为什么可以做到最长路径不会超过最短路径的两倍呢?

  • 特性4决定了路径不能有两个相连的红色节点;
  • 最短的可能路径都是黑色节点;
  • 最长的可能路径是红色和黑色交替;
  • 特性5所有路径都有相同数目的黑色节点;
  • 这就表明了没有路径能多余任何其他路径的两倍长;

三. 红黑树的变换

插入一个新节点时,有可能树不再平衡,可以通过三种方式的变换让树保持平衡:

3.1 变色:

为了重新符合红黑树的规则,尝试把红色节点变为黑色,或者把黑色节点变为红色;

  • 首先需要知道插入的新的节点通常都是红色节点
  • 因为在插入节点为红色的时候,有可能不违反红黑树任何规则;
  • 而插入黑色节点,必然会导致一条路径上多了黑色节点,这是很难调整的;
  • 红色节点可能导致出现红红相连的情况,但是这种情况可以通过颜色调换和旋转来调整。

3.2 旋转

3.2.1 左旋转

逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子。

1637984224682.png

图中,身为右孩子的Y取代了X的位置,而X变成了Y的左孩子,把b推过来,此为左旋转。

3.2.2 右旋转

1637984246526.png

图中,身为左孩子的Y取代了X的位置,而X变成了Y的右孩子,把c推过来,此为右旋转。

如果它们有子树也不影响旋转。

四. 插入操作的情况分析

设要插入的节点为N,其父节点为P,祖父节点为G,其兄弟节点为U(即P和U是同一个节点的子节点)

1637988196360.png

4.1 情况一

新节点N位于树的根上,没有父节点。

  • 这种情况下,我们直接将红色变换成黑色即可,这样满足特性2

4.2 情况二

新节点的父节点P是黑色。

  • 特性4没有失效(新节点是红色的),特性5也没有问题;
  • 尽管新节点N有两个黑色的叶子节点nil,但是新节点N是红色的,所以通过它的路径中黑色节点的个数依然相同,满足特性5。

4.3 情况三

  • P为红色,U也是红色;
  • 父红叔红祖黑 转换为 父黑叔黑祖红

1637991285664.png

可能出现的问题:

  • N的祖父节点,G的父节点也可能是红色,这就违反了特性3,可以递归调整颜色;
  • 如果递归调整到了根节点,就需要进行旋转了,文章最后例子中会遇到这个问题。

4.4 情况四

  • N的叔叔U是黑节点,且N是左孩子;
  • 父红叔黑祖黑,N是左孩子。

需要转为:父黑 祖红 再右旋转

1637992710320.png

操作流程

  • 交换以前的父节点P和祖父节点G的颜色(P为黑色,G变成红色。G原来一定是黑色);
  • 对祖父节点进行依次右旋转;
  • 旋转后的树中,以前父节点P现在是N之前祖父节点G的父节点;
  • B节点向右平移,成为G节点的左子节点。

4.5 情况五

  • N的叔叔U是黑节点,且N是右孩子;
  • 父红叔黑祖黑,N是右孩子。

1637993607434.png
操作方案:

  • 对P节点进行依次左旋转,形成情况四的结果;
  • 对祖父节点G进行依次右旋转,并且改变颜色即可

操作流程:

  • 以P为根,左旋转;

    • 将P作为新插入的红色节点考虑即可
  • 自己变成黑色;
  • 祖变成红色;
  • 以祖为根,进行右旋转。

五. 红黑树的案例

案例:依次插入10 9 8 7 6 5 4 3 2 1

模拟对树的操作:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

1637996838618.png

开始

  • 插入10

    • 将节点10的颜色改成黑色。

1637994297014.png

  • 插入9

    • 符合情况2
    • 不需要任何变化

1637994350842.png

  • 插入8

    • 符合情况4

1637994492699.png

  • 插入7

    • 符合情况3;
    • 变颜色后根节点为红,需要变黑。

1637995957505.png

  • 插入6

1637996096712.png

  • 插入5

1637996120402.png

  • 插入4

1637996174211.png

  • 插入3

1637996534023.png

  • 插入2

1637996552929.png

  • 插入1

1637996581990.png

转自coderwhy:https://www.jianshu.com/p/00aae4f4d672

评论(0)


最新评论

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • @@5Qa2D

    1

  • 1

    1

  • 1

    1

日历

2025年09月

 123456
78910111213
14151617181920
21222324252627
282930    

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis