红黑树

红黑树是一棵二叉搜索树,拥有二叉搜索树的性质:左子树的所有值小于根节点,右子树的所有值大于根节点。同时还具有近似平衡性质,近似平衡指的是任何节点的左右子树高度不会超过一半。它相对平衡二叉树的优势在于,任何不平衡都可以在三次之内的旋转解决,而平衡二叉树最坏会达到树的高度级别的旋转次数。

红黑树的性质

红黑树节点除了左节点,右节点,关键字的值三个基本二叉树元素之外,还维护了红黑色作为标记。同时null被定义成为叶子节点,具有关键字的节点被定义成为内部节点。

红黑树通过以下的性质维护红黑特性:

  1. 每个节点是红色的,或者黑色的
  2. 根节点是黑色的
  3. 叶子节点null是黑色的
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的,也就是不能有连续两个红节点
  5. 从任意内部节点出发,到达它的每个叶子节点,每条路径经过的黑色节点的数量是相同的

从某个节点xx出发(不包含该节点)到达一个叶节点的任意一条简单路径上的黑色节点个数称为该节点的黑高,记为hx(x)hx(x),定义null的黑高为0

算法学习13——红黑树

一个有n个内部节点的红黑树的高度至多是2lg(n+1)2lg(n+1)

**证明:**先证明以任一节点x为根的子树中至少包含2hb(x)12^{hb(x)}-1个内部节点。节点x的黑高是hb(x)hb(x),这个树拥有最少节点的情况是不具有红节点,那么它的黑高就等同于它的树高。该树的最后一层全是null,因此节点为x的树至少拥有2hb(x)12^{hb(x)}-1个内部节点。根据性质4,不能有连续两个红节点,因此高度为hh的红黑树,黑高至少为h/2h/2,根据上述证明可得:
n2hb(x)12h/21 n\ge 2^{hb(x)}-1 \ge 2^{h/2}-1
由上式可得
n2h/21n+12h/2log(n+1)h/22log(n+1)h n\ge2^{h/2}-1\\ n+1\ge2^{h/2}\\ log(n+1)\ge h/2\\ 2log(n+1)\ge h
因此高度最多为2log(n+1)2log(n+1)

红黑树的插入

红黑树的插入可分为2种场景讨论:

  1. 插入节点的父节点是黑色,那插入节点本身就是红色,符合性质,不需要改动

  2. 插入节点的父节点是红色,插入节点是红色,那么存在两个连续的红色,需要进行变色和旋转,由各自分为3种情况

    1. 父亲节点的兄弟节点是黑色,插入节点位于外侧(即如果父亲节点在祖父节点的左侧,插入节点就在父亲节点左侧;父亲节点在祖父节点右侧,那么插入节点在祖父节点右侧),如下图所示:

      算法学习13——红黑树

      其中x是插入节点,为了一般化,考虑x是个树情况;p是x的父节点;s是x的兄弟节点,同样考虑s是树的情况,并且由于父节点是红色,那么s只能是黑色;g是祖父节点,b是父亲节点的兄弟节点,当前情况下它是黑色,考虑b是个树的情况。它们的黑高具有以下性质:
      bh(x)1=bh(p)1=bh(g)1=bh(s)=bh(b) bh(x)-1=bh(p)-1=bh(g)-1=bh(s)=bh(b)
      其中bh(x)=bh(p)=bh(g)bh(x)=bh(p)=bh(g)是因为,p是红节点,g经过p节点没有新增黑色节点,所以p的黑高等于g的黑高。同理x的黑高等于p的黑高。

      而g经过s节点时,由于s是黑色节点,那么就新增了一个黑色节点,所以bh(p)1=bh(s)bh(p)-1=bh(s)。节点b也是类似的情况。通过以下的变换可以回归平衡状态:

      算法学习13——红黑树

      验证平衡过程的正确性:

      1. 首先1,2,3性质显然满足
      2. 原先唯一的连续两个红节点是x和p,通过变色和旋转已经解决了,满足性质4
      3. 由于没有对x,s,b树内进行更改,因此x,s,b的黑高没有发生变化,所以bh(x)=bh(s)=bh(b)bh(x)=bh(s)=bh(b),虽然p和g的树内发生了改动,由于bh(s)=bh(b)bh(s)=bh(b),所以bh(g)bh(g)还是等于bh(s)+1bh(s)+1,并且g被改成了红色节点,所以p的树高还是等于bh(g)bh(g)。因此性质5依旧满足。
    2. 父亲节点的兄弟节点是黑色,插入节点位于内侧(即如果父亲节点在祖父节点的左侧,插入节点就在父亲节点右侧;父亲节点在祖父节点右侧,那么插入节点在祖父节点左侧),如下图所示:

      算法学习13——红黑树

      其中x是插入节点,为了一般化,考虑x是个树情况,l和f是x的两个左右子树,因为x是红节点,所以l和x都是黑节点;p是x的父节点;s是x的兄弟节点,同样考虑s是树的情况,并且由于父节点是红色,那么s只能是黑色;g是祖父节点,b是父亲节点的兄弟节点,当前情况下它是黑色,考虑b是个树的情况。它们的黑高具有以下性质:
      bh(x)1=bh(p)1=bh(g)1=bh(s)=bh(b)=bh(l)=bh(r) bh(x)-1=bh(p)-1=bh(g)-1=bh(s)=bh(b)=bh(l)=bh(r)

      平衡思路是先将当前情况转换成为情况1进行处理:

      算法学习13——红黑树

      验证平衡正确性:

      1. 首先1,2,3性质显然满足
      2. 转移成为情况1的状态,没有满足不能连续两个红节点的特性,需要用情况1的策略继续进行
      3. 黑高特性没有发现改变
    3. 父节点的兄弟节点是红色。如下图所示:

      算法学习13——红黑树

      与情况1不同,b是个红色节点,他们的黑高具有以下性质:
      bh(x)1=bh(p)1=bh(b)1=bh(g)1=bh(s) bh(x)-1=bh(p)-1=bh(b)-1=bh(g)-1=bh(s)
      这种时候分为两种状态进行操作:

      1. 如果祖父g已经是根节点了

        算法学习13——红黑树

        其中节点x,s,b,p的黑高没有发生变化,而由于p和b变成了黑节点,g的黑高增加1

      2. 如果祖父g不是根节点

        算法学习13——红黑树

        与上面状态不同的是,祖父g需要更新为红色节点。

      为什么要考虑根节点进行不同操作呢?如果g是根节点,根节点无法是红色节点,所以必须是黑色节点;如果g不是根节点,并且g还是黑色的话,相对g的父节点来说,由于p和b变成了黑色,g的父节点的黑高就加1了,变得无法平衡。因此g需要变成红色节点,作为p和b变成黑色节点的补偿。

证明它的插入最多三次旋转变换:

  1. 如果是第一种场景,父节点是黑色,插入节点是红色,直接成立
  2. 如果是第二种场景的第一种情形,父节点也是红色,父节点的兄弟节点是黑色,经过一次旋转可以达到平衡
  3. 如果是第二种场景的第二种情形,父节点也是红色,父节点的兄弟节点是红色,但是插入节点在内侧,经过一次转换变成上述2,再经过一次旋转可以达到平衡,总共经过2次旋转
  4. 如果是第二种场景的第三张情形,当祖父节点是根节点时,经过一次旋转可以达到平衡;如果祖父节点不是根节点,并且祖父节点的父节点是黑色的话直接达到平衡,也是一次旋转达到平衡;如果祖父节点不是根节点,并且祖父节点的父节点是红色,那么祖父节点的兄弟节点必然是黑色,经过一次旋转后变成上述2或者3,最多再经过1次(上述2)或者2次(上述3)旋转可以达到平衡,总体经过了2次或者3次旋转

因此最多经过3次旋转可以达到平衡。

相关文章:

  • 2021-12-29
  • 2022-12-23
  • 2021-08-08
  • 2021-07-13
  • 2021-07-06
  • 2022-12-23
  • 2021-11-10
猜你喜欢
  • 2022-02-12
  • 2022-12-23
  • 2021-06-22
  • 2021-08-31
  • 2022-12-23
  • 2021-12-07
  • 2021-08-15
相关资源
相似解决方案