第 13 章 紅黑樹

  二叉搜索樹在樹的高度較高時,動態集合的操作可能並不比在鏈表上執行的快。紅黑樹是許多“平衡”搜索樹的一種,可以保證在最壞情況下基本動態集合操作的時間複雜度爲O(lgn)。
  

13.1 紅黑樹的性質

  紅黑樹是一顆二叉搜索樹,它在每個結點上增加了一個存儲位來表示結點的顏色,可以是RED或BLACK。通過對任何一條從根到葉子的簡單路徑上各個結點的顏色進行約束,紅黑樹確保沒有一條路徑會比其他路徑長出 2 倍,因而是近似於平衡的
  樹中每個結點包含 5 個屬性:color、key、left、right和p。如果一個結點沒有子結點或父結點,則該結點相應指針屬性的值爲NIL。可以把這些NIL視爲指向二叉搜索樹的葉結點(外部結點)的指針,而把帶關鍵字的結點視爲樹的內部結點。
  一顆紅黑樹是滿足下面紅黑性質的二叉搜索數:
  

  1. 每個結點或是紅色的,或是黑色的。
  2. 根結點是黑色的。
  3. 每個葉結點(NIL)是黑色的。
  4. 如果一個結點是紅色的,則它的兩個子節點是黑色的。
  5. 對每個結點,從該結點到其所有後代葉結點的簡單路徑上,均包含相同數目的黑色結點。
      爲了便於處理紅黑樹代碼中的邊界條件,使用一個哨兵來代表NIL。對於一顆紅黑樹 T,哨兵 T.nil是一個與樹中普通結點有相同屬性的對象。它的color屬性爲BLACK,而其他屬性可以爲任意值。使用一個哨兵 T.nil來代表說有的NIL:所有的葉節點和根節點的父節點。
      從某個結點 x 出發(不含該結點)到達一個葉結點的任意一條簡單路徑上的黑色結點個數稱爲該結點的黑高,記爲bh(x)。黑高的概念是明確定義的,因爲從該結點出發的所有下降到其葉結點的簡單路徑的黑結點個數都相同。於是,定義紅黑樹的黑高爲其根節點的黑高。
      引理13.1 一顆有 n 個內部結點的紅黑樹的高度至多爲2lg(n+1)。
      由該引理可知,動態集合操作可在紅黑樹上在O(lgn)時間內執行。因爲這些操作在一顆高度爲 h 的二叉搜索樹上的運行時間爲O(h),而任何包含 n 個結點的紅黑樹又都是高度爲O(lgn)的二叉搜索樹。

13.2 旋轉

  搜索數操作TREE-INSERT和TREE-DELETE在含 n 個關鍵字的紅黑樹上,運行花費時間爲O(lgn),由於這兩個操作對數做了修改,結果可能違反紅黑樹性質。,爲了維護這些性質,必須要改變樹中某些結點的顏色以及指針結構。
  指針結構的修改是通過旋轉來完成的,這是一種能保持二叉搜索樹性質的搜索樹局部操作。包括兩種旋轉:左旋和右旋。當在某個結點 x 上做左旋時,假設它的右孩子爲 y 而不是T.nil; x 可以爲其右孩子不是T.nil結點的樹內任意結點。 左旋以 x 到 y 的鏈爲“支軸”進行。它使 y 成爲該子樹新的根結點,x 成爲 y 的左孩子,y 的左孩子成爲 x 的右孩子。
  這裏寫圖片描述
  旋轉保持了二叉搜索樹的性質。在LEFT-ROTATE的僞代碼中,假設x.right != T.nil 且根節點的父結點爲T.nil。
  LEFT-ROTATE(T,x)
  

y = x.right
x.right = y.left
if y.left != T.nil
    y.left.p = x
y.p = x.p
if x.p == T.nil
    T.root = y
else if x == x.p.left
    x.p.left = y
else x.p.right = y
y.left = x
x.p = y

LEFT-RATATE在O(1)時間內完成。在旋轉操作中,只有指針改變,其他所有屬性都保持不變。

13.3 插入

  可以在O(lgn)時間內完成向一顆含 n 個結點的紅黑樹中插入一個新結點。調用 RB-INSERT(T,z)在紅黑樹 T 內插入結點 z,假設 z 的key屬性已被實現賦值。調用輔助程序RB-INSERT-FIXUP來對結點重新着色並旋轉,以保持紅黑樹性質。
RB-INSERT(T,z)

y = T.nil
x = T.root
while x != T.nil
    y = x
    if z.key < x.key
    x = x.left
    else x = x.right
a.p = y
if y == T.nil
    T.root = z
else if z.key < y.key
    y.left = z
else y.right = z
z.left = T.nil
z.right = T.nil
z.color = RED
RB-INSERT-FIXUM(T,z)

RB-INSERT-FIXUP(T,z)

while z.p.color == RED
    if z.p == z.p.p.left
        y = z.p.p.right
        if y.color == RED
            z.p.color = BLACK
            y.color = BLACK
            z.p.p.color = RED
            z = z.p.p
        else if z == z.p.right
            z = z.p
            LEFT-ROTATE(T, z)
        z.p.color = BLACK
        z.p.p.color = RED
        RIGHT-ROTATE(T, z.p.p)
    else (same as then clause
            with "right“ and "left" exchanged)
T.root.color = BLACK    

13.4 刪除

  紅黑樹刪除一個結點要花費O(lgn)時間。與插入操作相比,刪除操作要複雜。
  首先定義一個子過程RB-TRANSPLANT:
  
RB-TRANSPLANT(T, u, v)

if u.p == T.nil
    T.root = v
else if u == u.p.left
    u.p.left = v
else u.p.right = v
v.p = u.p

RB-DELETE(T, z)

y = z
y-original-color = y.color
if z.left == T.nil
    x = z.right
    RB-TRANSPLANT(T,z, z.right)
else if z.right == T.nil
    x = z.right
    RB-TRANSPLANT(T, z, z.left)
else y = TREE-MINIMUM(z.right)
    y-original-color = y.color
    x = y.right
    if y.p == z
        x.p = y
    else RB-TRANSPLANT(T, y, y.right)
        y.right = z.right
        y.right.p = y
    RB-TRANSPLANT(T, z, y)
    y.left = z.left
    y.left.p = y
    y.color = z.color
if y-original-color == BLACK
    RB-DELETE-FIXUP(T,x)

RB-DELETE調用一個輔助過程RB-DELETE-FIXUP,該過程通過改變顏色和執行旋轉來恢復紅黑性質。
RB-DELETE-FIXUP(T,x)

while x != T.root and x.color == BLACK
    if x == x.p.left
        w = x.p.right
        if w.color == RED
            w.color = BLACK
            x.p.color = RED
            LEFT-ROTATE(T, x.p)
            w = x.p.right
        if w.left.color == BLACK and w.right.color == BLACK
            w.color = RED
            x = x.p
        else if w.right.color == BLACK
                w.left.color = BLACK
                w.color = RED
                RIGHT-ROTATE(T, w)
                w = x.p.right
            w.color = x.p.color
            x.p.color = BLACK
            w.right.color = BLACK
            LEFT-ROTATE(T,x.p)
            x = T.root
    else(same as then clause with "right" and "left" exchanged)
x.color = BLACK
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章