将 AVL 树转换为红黑树

Posted

技术标签:

【中文标题】将 AVL 树转换为红黑树【英文标题】:Convert AVL Trees to Red Black tree 【发布时间】:2016-03-18 03:38:22 【问题描述】:

我在某处读到此声明,任何 AVL 树 T 的节点都可以被着色为“红色”和“黑色”,这样 T 就变成了红黑树。

这个陈述似乎很有说服力,但我不明白如何正式证明这个陈述。

根据wiki,一棵红黑树应该满足这五个属性:

a.一个节点不是红色就是黑色。

b.根是黑色的。这条规则有时会被省略。由于根总是可以从红色变为黑色,但不一定反过来,

c。所有叶子 (NIL) 都是黑色的。

d.如果一个节点是红色的,那么它的两个子节点都是黑色的。

e.从给定节点到其任何后代 NIL 节点的每条路径都包含相同数量的黑色节点。

四个条件很简单,我卡住了如何证明语句5

【问题讨论】:

【参考方案1】:

首先,定义树的高度(用于 AVL 树):

height(leaf) = 1
height(node) = 1 + max(height(node.left), height(node.right))

此外,定义路径的深度(如用于红黑树,路径是从给定节点到某个叶子的后代链)到是路径上的黑色节点数。


正如您所指出的,将 AVL 树着色为红黑树的棘手之处在于确保每条路径都具有相同的深度。您将需要使用 AVL 不变量:任何给定节点的子树的高度最多只能相差一个。

直观地说,诀窍是使用一种着色算法,其深度对于给定的高度是可预测的,这样您就不需要进行任何进一步的全局协调。然后,您可以局部调整着色,以确保每个节点的子节点具有相同的深度;这是可能的,因为 AVL 条件严格限制了它们的高度差。


这种树着色算法可以解决问题:

color_black(x):
  x.color = black;
  if x is a node:
    color_children(x.left, x.right)

color_red(x):  // height(x) must be even
  x.color = red
  color_children(x.left, x.right)  // x will always be a node

color_children(a,b):
  if height(a) < height(b) or height(a) is odd:
    color_black(a)
  else:
    color_red(a)
  if height(b) < height(a) or height(b) is odd:
    color_black(b)
  else:
    color_red(b)

对于 AVL 树的根,调用color_black(root) 以确保 b. 请注意,树是按深度优先顺序遍历的,同时也确保了一个。

请注意,红色节点的高度都是均匀的。叶子的高度为 1,因此它们将被着色为黑色,确保 c。红色节点的子节点要么有奇数高度,要么比他们的兄弟节点矮,并且将被标记为黑色,以确保 d。

最后,显示 e。 (来自根的所有路径都具有相同的深度), 在n&gt;=1 上使用归纳法来证明:

为奇数height = 2*n-1, color_black() 创建一个红黑树,深度为n 即使height = 2*n, color_red() 将所有路径设置为深度n color_black() 创建深度为n+1 的红黑树

基本情况,对于n = 1

对于奇数height = 1,树是叶子; color_black() 将叶子设置为黑色;唯一路径的深度为 1, 对于偶height = 2,根是一个节点,两个孩子都是叶子,如上标记为黑色; color_red() 将节点设置为红色;两条路径的深度均为 1 color_black() 将节点设置为黑色;两条路径的深度均为 2

归纳步骤是我们使用 AVL 不变量的地方:兄弟树的高度最多可以相差 1。对于具有给定 height 的节点:

子案例A:两个子树都是(height-1) 子案例B:一个子树是(height-1),另一个是(height-2)

归纳步骤:假设n 为真,证明它适用于n+1

对于奇数height = 2*(n+1)-1 = 2*n+1

子案例A:两个子树的高度相等2*n color_children() 为两个孩子调用 color_red(), 通过归纳假设,两个孩子都有深度n 对于父节点,color_black() 添加一个黑色节点,对于深度n+1 子案例 B:子树的高度为 2*n2*n-1 color_children() 分别调用 color_red() 和 color_black(); 对于均匀高度2*n,color_red() 产生深度n(感应炒作) 对于奇数高度2*n-1,color_black() 产生深度n(感应炒作) 对于父节点,color_black() 添加一个黑色节点,对于深度n+1

甚至height = 2*(n+1) = 2*n + 2

子案例A:两个子树的高度都是奇数2*n+1 = 2*(n+1)-1 color_children() 为两个孩子调用 color_black() 以获取深度 n+1 从上面奇高的情况下,两个孩子都有深度n+1 对于父节点,color_red() 添加一个红色节点,深度不变n+1 对于父节点,color_black() 添加一个黑色节点,对于深度n+2 子案例 B:子树的高度为 2*n+1 = 2*(n+1)-12*n color_children() 为两个孩子调用 color_black() 以获取深度 n+1 对于奇数高度2*n+1,color_black() 产生深度n+1(见上文) 对于均匀高度2*n,color_black() 产生深度n+1(感应炒作) 对于父节点,color_red() 添加一个红色节点,对于深度n+1 对于父节点,color_black() 添加一个黑色节点,对于深度n+2 = (n+1)+1

【讨论】:

【参考方案2】:

好吧,#5 的简单情况是单个后代,它是一片叶子,在 #3 之前它是黑色的。

否则,后代节点为红色,到#4时要求有2个黑色后代。

然后这两种情况递归地应用于每个节点,因此您将始终在每条路径中拥有相同数量的黑色节点。

【讨论】:

你在哪里使用 AVL 不变量? @comingstorm - OP 不需要知道如何 转换【参考方案3】:

即使可以将AVL树转换为红黑树,代价也是非常大的。树的形状与内部结构无关,需要彻底重建。

红黑树的最大局部高差界限为2。

【讨论】:

以上是关于将 AVL 树转换为红黑树的主要内容,如果未能解决你的问题,请参考以下文章

简述AVL树红黑树B/B+树Trie树

二叉排序树红黑树AVL树散列表

B树B+树红黑树AVL树比较

树结构系列:平衡二叉树AVL树红黑树

二叉树红黑树以及Golang实现红黑树

AVL树红黑树以及B树介绍