将AVL树转换为红黑树

时间:2015-12-12 06:00:21

标签: algorithm data-structures tree avl-tree red-black-tree

我在某处读到这句话,任何AVL树T的节点都可以是“红色”和“黑色”,这样T就会变成红黑树。

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

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

a.A节点为红色或黑色。

b。根是黑色的。有时会省略此规则。由于根总是可以从红色变为黑色,但不一定相反,

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

d。如果节点为红色,则其子节点均为黑色。

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

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

2 个答案:

答案 0 :(得分:3)

首先,定义树的高度(用于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。 (来自root的所有路径都具有相同的深度), 在n>=1上使用归纳来证明:

  • for odd height = 2*n-1
    • color_black()创建一个红黑树,深度为n
  • for even 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的节点:

  • subcase A:两个子树都是(height-1)
  • subcase B:一个子树为(height-1),另一个为(height-2)

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

表示奇height = 2*(n+1)-1 = 2*n+1

  • subcase A:两个子树的高度均为2*n
    • color_children()为两个孩子调用color_red(),
    • 通过归纳假设,两个孩子都有深度n
    • 表示父级,color_black()为深度n+1
    • 添加黑色节点
  • subcase B:子树的高度为2*n2*n-1
    • color_children()调用color_red()和color_black(),resp;
    • 对于偶数高度2*n,color_red()会产生深度n(感应效果)
    • 对于奇数高度2*n-1,color_black()会产生深度n(感应效果)。
    • 表示父级,color_black()为深度n+1
    • 添加黑色节点

表示偶数height = 2*(n+1) = 2*n + 2

  • subcase A:两个子树都有奇数高度2*n+1 = 2*(n+1)-1
    • color_children()为两个孩子调用color_black(),深度为n+1
    • 从上面的奇数高度案例中,两个孩子都有深度n+1
    • 表示父级,color_red()添加一个红色节点,用于未更改的深度n+1
    • 表示父级,color_black()为深度n+2
    • 添加黑色节点
  • subcase 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
    • 添加黑色节点

答案 1 :(得分:1)

嗯,#5的简单情况是单个后代,它是一个叶子,#3是黑色的。

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

然后这两个案例递归地应用于每个节点,因此您在每个路径中始终具有相同数量的黑色节点。