《算法导论3rd第十三章》红黑树

前言

红黑树是一种较为“平衡的”二叉查找树。它能保证最坏的情况下其基本操作时间为O(lgn).

红黑树的性质

红黑树 是一种二叉查找树,但在每个结点上增加了一个存储位表示结点的颜色,可以是 RED 或 BLACK 。通过对任何一条从根到叶子的路径上的各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
树中每个结点包含五个域: color , key , left , right 和 p 。如果某结点没有一个子结点或父结点,则该结点相应的指针为 NIL 。我们将这些 NIL 视为指向二叉查找树外结点(叶子)的指针,而把带关键字的结点视为树的内结点。

一棵红黑树需要满足下面的 红黑性质 :

  1. 每个结点或是红的,或是黑的。
  2. 根结点是黑的。
  3. 每个叶结点( NIL )是黑的。
  4. 如果一个结点是红的,则它的两个孩子都是黑的。
  5. 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
    在这里插入图片描述

通常我们将注意力放在红黑树的内部结点上,因为它们存储了关键字的值。因此本文其余部分都将忽略红黑树的叶子

引理13.1 一棵有n个内结点的红黑树的高度至多为2lg(n+1).

练习

1-1 使用图13-1a的格式,画出在关键字集合{1,2,…,15}上高度为3的完全二叉查找树。以三种不同方式,向图中加入NIL叶结点并对各结点着色,使所得的红黑树的黑高度分别为2,3,4.

在这里插入图片描述

1-2对图13-1中的红黑树,画出调用TREE-INSERT插入关键字36后的结果。结果插入的结点被标为红色,所得的树是否还是一棵红黑树?如果该结点被标为黑色呢?

  • 标为红色后,不是红黑树,不符合性质4.
  • 标为黑色后,不是红黑树,不符合性质5.

1-3 定义松弛红黑树为满足红黑性质1,3,4,5的二叉查找树。换言之,根部可以是红色或是黑色。考虑一棵根是红色的松弛红黑树T。如果将T的根部标为黑色而其他都不变,则所得到的是否还是一棵红黑树?

是。节点变了色后1,3,4,5性质也满足。

1-4

(略)

1-5 证明:在一棵红黑树中,从某结点x到其后代叶结点的所有简单路径中,最长的一条是最短一条的至多两倍。

性质4,5决定。最短:此路径上全是黑色结点。最长:此路径上红黑结点交替出现(红色结点数目=黑色结点数目)

1-6 在一棵黑高度为k的红黑树中,内结点最多可能有多少个?最少可能有多少个?

根据引理13.1 至少包含 2 k − 1 2^k-1 2k1个内部结点。至多包含 2 2 k − 1 个 2^{2k}-1个 22k1内部结点。(最多就是红黑结点交替出现的情况)

1-7 请描述出一棵在n个关键字上构造出来的红黑树,使其中红的内部结点数与黑的内部结点数比值最大。这个比值是多少?具有最小可能比例的树又是怎么样?此比值是多少?

最小可能比值就是所有结点都是黑色,比值为0。 最大可能是红黑结点交替出现,并且最底层是全部是红色结点,比值是2:1.

旋转

当在含 n 个关键字的红黑树上运行时,查找树操作 TREE-INSERT 和 TREE-DELETE 的时间为 O ( lg n )。由于这两个操作对树做了修改,结果可能违反了红黑树的性质,为保持红黑树的性质,就要改变树中某些结点的颜色和指针结构。指针结构的修改是通过 旋转 来完成的,这是一种能保持二叉查找树性质的查找树局部操作。
在这里插入图片描述

LEFT-ROTATE(T, x)
 y = x.right            // set y
 x.right = y.left       // turn y's left subtree into s's right subtree
 if y.left != T.nil
     y.left.p = x
 y.p = x.p
 if x.p == T.nil
     T.root = y
 elseif x == x.p.left
     x.p.left = y
 else
     x.p.right = y
 y.left = x             // put x on y's left
 x.p = y

练习

2-1 写出RIGHT-ROTATE的伪代码。

RIGHT-ROTATE(T, y)
    x = y.left
    y.left = x.right
    if x.right != T.nil
        x.right.p = y
    x.p = y.p
    if y.p == T.nil
        T.root = x
    else if y == y.p.right
        y.p.right = x
    else y.p.left = x
    x.right = y
    y.p = x

2-2 证明:在一棵有n个结点的二叉查找树中,刚好有n-1种可能的旋转。

因为n个结点有n-1条边,每条边都可以(左或右)旋转,所以有n-1种可能的旋转。

2-3

(略)

2-4 证明:任何一棵含n个结点的二叉查找树,可以通过O(n)次旋转,转变为另一棵含n个结点的二叉查找树。

每次右(左)旋转,都会使最右(左)链上多一个结点,经过任意n-1次右(左)旋转,任意右(左)总会变成一个单链表。

插入

向一棵含 n 个结点的红黑树 T 中插入一个新结点 z。首先将结点 z 插入树 T 中,就好像 T 是一棵普通的二叉查找树一样,然后将 z 着为红色。

RB-INSERT(T, z)
1  y = T.nil
2  x = T.root
3  while x != T.nil
4      y = x
5      if z.key < x.key
6          x = x.left
7      else
8          x = x.right
9  z.p = y
10 if y == T.nil
11     T.root = z
12 elseif z.key < y.key
13     y.left = z
14 else
15     y.right = z
16 z.left = T.nil
17 z.right = T.nil
18 z.color = RED
19 RB-INSERT-FIXUP(T, z)

为保证红黑性质,这里要调用一个辅助程序 RB-INSERT-FIXUP 来对结点重新着色并旋转.

RB-INSERT-FIXUP(T, z)
1  while z.p.color == RED
2      if z.p == z.p.p.left                              // z的父结点是其父结点的左孩子
3          y = z.p.p.right                               // 令y为z的叔父结点
4          if y.color == RED
5              z.p.color = BLACK                         // case 1
6              y.color = BLACK                           // case 1
7              z.p.p.color = RED                         // case 1
8              z = z.p.p                                 // case 1
9          else
10             if z == z.p.right
11                 z = z.p                               // case 2
12                 LEFT-ROTATE(T, z)                     // case 2
13             z.p.color = BLACK                         // case 3
14             z.p.p.color = RED                         // case 3
15             RIGHT-ROTATE(T, z.p.p)                    // case 3
16     else                                              // z的父结点是其父结点的右孩子
17         y = z.p.p.left                                // 令y为z的叔父结点
18         if y.color = RED
19             z.p.color = BLACK
20             y.color = BLACK
21             z.p.p.color = RED
22             z = z.p.p
23         else
24             if z = z.p.left
25                 z = z.p
26                 RIGHT-ROTATE(T, z)
27             z.p.color = BLACK
28             z.p.p.color = RED
29             LEFT-ROTATE(T, z.p.p)
30 T.root.color = BLACK

具体情况参考红黑树-插入

练习

3-1在RB_INSERT的第16行中,假设新插入的结点z是红的。注意如果将z着为黑色,则红黑树性质4就不会被破坏。那么我们为什么没有选择将z着为黑色呢?

如果z着为黑色,那么性质5会被破坏,红黑树调整起来会更复杂。

3-2在将关键字48,38,31,12,19,8插入一棵初始为空的红黑树中之后,结果树是什么样子?

在这里插入图片描述

3-3

(略)

3-4

(略)

3-5 考虑用RB_INSERT插入n个结点而成的一棵红黑树。证明:如果n>1,则该树至少有一个红结点。

假设前n-1个插入结点后都为黑色 满足红黑树性质,那么第n个结点插入后,必须是红色。否则违反性质5.

3-6说明如果红黑树的表示中不提供父指针的话,应当如何有效地实现RB_INSERT.

使用栈。

删除

删除操作运行时间也是O(lgn).并且比插入操作复杂。

RB-DELETE(T, z)
1  y = z
2  y-original-color = y.color
3  if z.left == T.nil
4      x = z.right
5      RB-TRANSPLANT(T, z, z.right)
6  elseif z.right == T.nil
7      x = z.left
8      RB-TRANSPLANT(T, z, z.left)
9  else
10     y = TREE-MINIMUM(z.right)
11     y-original-color = y.color
12     x = y.right
13     if y.p == z
14         x.p = y
15     else
16         RB-TRANSPLANT(T, y, y.right)
17         y.right = z.right
18         y.right.p = y
19     RB-TRANSPLANT(T, z, y)
20     y.left = z.left
21     y.left.p = y
22     y.color = z.color
23 if y-original-color == BLACK
24     RB-DELETE-FIXUP(T, x)

还要调用 RB-DELETE-FIXUP 以保持红黑性质

RB-DELETE-FIXUP(T, x)
1  while x != T.root and x.color == BLACK
2      if x == x.p.left
3          w = x.p.right
4          if w.color == RED
5              w.color = BLACK                                          // case 1
6              x.p.color = RED                                          // case 1
7              LEFT-ROTATE(T, x.p)                                      // case 1
8              w = x.p.right                                            // case 1
9          if w.left.color == BLACK and w.right.color == BLACK
10             w.color = RED                                            // case 2
11             x = x.p                                                  // case 2
12         else
13             if w.right.color == BLACK
14                 w.left.color = BLACK                                 // case 3
15                 w.color = RED                                        // case 3
16                 RIGHT-ROTATE(T, w)                                   // case 3
17                 w = x.p.right                                        // case 3
18             w.color = x.p.color                                      // case 4
19             x.p.color = BLACK                                        // case 4
20             w.right.color = BLACK                                    // case 4
21             LEFT-ROTATE(T, x.p)                                      // case 4
22             x = T.root                                               // case 4
23     else (same as then clause with "right" and "left" exchanged)
24 x.color = BLACK

具体情况参考红黑树-删除

练习

4-1 在执行RB_DELETE-FIXUP之后,证明:树根一定是黑色的。

  • Case 1: transform to 2, 3, 4.
  • Case 2: if terminates, the root of the subtree (the new xx) is set to black.
  • Case 3: transform to 4.
  • Case 4: the root (the new xx) is set to black.

4-2在RB_DELETE中,如果x和x.p都是红色的。证明:可以通过调用RB_DELETE_FIXUP(T,x)来恢复性质4.

x和x.p都为红色,那么不进入循环,直接最后把x着为黑色以恢复性质4.。

4-3在练习13.3-3中,将关键字41,38,31,12,19,8连续插入一棵初始的空树中,从而得到一棵红黑树。请给出从该树中连续删除关键字8,12,19,31,38,41后的红黑树。

  • 删除8在这里插入图片描述
  • 删除12在这里插入图片描述
  • 删除19在这里插入图片描述

4-[4,5,6]

(略)

4-7 假设用RB_INSERT将一个结点x插入一棵红黑树,紧接着又用RB_DELETE将它从树中删除。结果的红黑树与初始红黑树是否一样?证明你的答案。

在这里插入图片描述

思考题

  • 13-1 持久动态集合
  • 13-2 红黑树的连接操作
  • 13-3 AVL树
  • 13-4 Treap树

主要参考

算法导论读书笔记(13)
Red-Black Trees
算法导论第13(十三)章红黑树

Guess you like

Origin blog.csdn.net/y3over/article/details/121624880