JS数据结构与算法—红黑树

250 阅读4分钟

红黑树-平衡二叉搜索树

二叉搜索树的缺陷

  • 当插入连续的数据时,如key为9,8,7,6,5或1,2,3,4,5等,二叉搜索树会很不平衡,会极大影响树结构查找、插入的效率。直接由O(logN)下降为O(N).
  • 一般会选择AVL树或者红黑树来保持树的平衡,并且红黑树在插入、删除等操作的性能要优于AVL树。

红黑树的规则

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

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

红黑树的相对平衡

  • 从根到叶子的最长可能路径,不会超过最短可能路径的两倍长
  • 结果就是这个树基本是平衡的虽然没有做到绝对的平衡,但是可以保证在最坏的情况下,依然是高效的
  • 为什么可以做到最长的路径不超过最短路径的两倍长
    • 性质4决定了路径不能有两个相连的红色节点
    • 最短的可能路径都是黑色节点
    • 最长的可能路径都是黑色和红色交替
    • 性质5所有路径都有相同数目的黑色节点
    • 这就表明了没有路径能多余其他路径的两倍长

保持平衡的方法

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

  • 变色
    • 为了重新符合红黑树的规则,尝试把红色节点变为黑色、或者把黑色节点变为红色
    • 首先,插入的新的节点通常是红色节点。因为在插入节点为红色的时候,有可能插入依次是不违反红黑树任何规则,而插入黑色节点,必然会导致有一条路径上多了黑色节点,这是很难调整的
    • 红色节点可能导致出现红红相连的情况,但是这种情况可以通过颜色变换和旋转来调整
  • 左旋转
    • 逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子
    • 它们有子树是否会影响旋转? 答:不会
  • 右旋转
    • 顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子
    • 它们有子树是否会影响旋转?答:不会

插入操作的情况分析

首先插入的新节点默认为红色,N代表插入节点Node,P代表N的父节点ParentNode,U代表N的叔节点UncleNode,G代表N的祖父节点GrandeParentNode。

  • 情况一
    • 现象:新节点N位于树的根上,没有父节点
    • 做法:这种情况下,我们直接将红色变为黑色即可,这样满足性质2

1.png

  • 情况二
    • 现象:新节点的父节点P是黑色
    • 做法:性质四没有失效(新节点是红色的),性质5也没有人和问题。尽管新节点N有两个黑色的叶子节点NIL,但是新节点N是红色的,所以通过它的路径中黑色节点的个数依然相同,满足性质5。所以直接插入就可以。

image.png

  • 情况三
    • 现象:P为红色,U也是红色,G为黑色。

    • 做法:改变为 P黑,U黑,G红

    • 可能出现的问题:(1)G的父节点也可能是红色,这就违反了性质3,可以递归地调整颜色。(2)如果递归调整颜色到了根节点,就需要进行旋转了(见后例)

image.png

  • 情况四
    • 现象:父红,叔黑,祖黑,N是左儿子
    • 做法:变成父黑祖红,进行右旋转,(先变色再旋转)

image.png

  • 情况五
    • 现象:父红,叔黑,祖黑,且N是右儿子

    • 做法:先以P为根进行左旋转,将P作为新插入的红色节点考虑即可,此时同情况四,将自己变成黑色,祖父变成红色,以祖为根进行左旋转

image.png

插入数据案例

将10,9,8,7,6,5,4,3,2,1依次插入红黑树,过程示意图如下:

image.png

image.png

                                           参考coderwhy老师的数据结构