1. 程式人生 > >十三、紅黑樹

十三、紅黑樹

實際工程中,很多用到平衡二叉查詢樹的地方都是紅黑樹。
==》為何是紅黑樹?而不是其他平衡二叉查詢樹?

  • 其他二叉樹不適用於單次操作時間非常敏感的場景。
  • AVL樹對於頻繁的插入、刪除操作的資料集合代價有些高==》紅黑樹維護成本比AVL要低

一、平衡二叉查詢樹

平衡二叉樹二叉樹中任意一個節點的左右子樹的高度相差不能大於1。
完全二叉樹、滿二叉樹都是平衡二叉樹;但非完全二叉樹也可能是平衡二叉樹

在這裡插入圖片描述

AVL樹——最早被髮明的平衡二叉查詢樹

“平衡二叉樹”思想:解決普通二叉查詢樹在頻繁的插入、刪除等動態更新的情況下,出現時間複雜度退化的問題。
==》整棵樹左右更對稱些,不要出現左子樹很高、右子樹很矮的情況,相應的插入、刪除、查詢等操作的效率高一些。
==》設計新的平衡二叉樹,只要樹的高度不比log2

n大很多,就可以說其實一個合格的平衡二叉樹。

1、紅黑樹(Red-Black Tree,簡稱R-B Tree)

  • 紅黑樹是一種不嚴格的平衡二叉查詢樹

(1)紅黑樹

  • 根節點是黑色的;
  • 每個葉子節點都是黑色的空節點(NIL),也就是說,葉子節點不儲存資料;
  • 任何相鄰節點都不能同時為紅色,也就是說,紅色節點被黑色節點隔開的;
  • 每個節點,從該節點到其可達葉子節點的所有路徑,都包含相同數目的黑色節點。
    在這裡插入圖片描述

(2)高度分析

  • 將紅色節點從紅黑樹中去掉,只留黑色節點
    ==》有些節點沒有父節點,它們會將這些節點的祖父節點作為父節點
    ==》會出現多叉樹(eg: 四叉樹的情況)
    ==》僅包含黑色節點的多叉樹的高度,比包含相同節點個數的完全二叉樹的高度要小


    ==》去掉紅色節點的“黑樹”的高度不超過log2n。
    在這裡插入圖片描述

  • 將紅色節點添加回去——紅色節點不能相鄰,也就是說有一個紅色節點就要至少有一個黑色節點,將其跟其他紅色節點隔開
    ==》高度不會超過2log2n,也就是說,紅黑樹的高度近似2log2n。

(3)小結

紅黑樹的高度只比高度平衡的AVL樹的高度(log2n)僅僅大了一倍,在效能上,下降得並不多。

二、平衡調整

1、左旋(rotate left)和右旋(rotate right)

紅黑樹的插入、刪除操作會破壞紅黑樹的定義,也就是說,會破壞紅黑樹的平衡性。

左旋:圍繞某個節點的左旋。
右旋:圍繞某個節點的右旋。

在這裡插入圖片描述

2、插入操作的平衡調整

紅黑樹規定:插入的節點必須是紅色的,而且新插入的節點必須放在葉子節點上。

(1)兩種特殊情況:

  • 若插入節點的父親節點是黑色的,則不需要做什麼。因為:它仍滿足紅黑樹的定義
  • 若插入的節點是根節點,則直接改變其顏色,將其變為黑色。
  • ==》其他情況,均違背紅黑樹的定義,則需要進行調整——左右旋轉、改變顏色

(2)平衡調整過程——迭代過程

關注關節:正在處理的節點。它會隨著不停地迭代處理,而不斷髮生變化。
==》最開始的關注節點就是新插入的接待呢

新節點插入後,若平衡被打破,則一般會出現下面三種情況:
(這裡,將父節點的兄弟節點稱為叔叔節點,父節點的父節點稱為祖父節點)

case1 : 若關注節點是 a,它的叔叔節點d是紅色,則

  • 將關注節點 a 的父節點 b 、叔叔節點 d 的顏色均設定為黑色;
  • 將關注節點 a 的祖父節點 c 的顏色設定為紅色;
  • 關注節點變成 a 的祖父節點 c ;
  • 跳轉case2 或者 case3
    在這裡插入圖片描述

case2:若關注節點是a,它叔叔節點d是黑色,關注節點a是其父節點b的右子節點,則:

  • 關注節點變為節點 a 的父節點 b;
  • 圍繞新的關注節點 b 左旋;
  • 跳轉 case3
    在這裡插入圖片描述

case3:若關注節點是 a,它叔叔節點 d 是黑色,關注節點 a 是其父節點b的左子結點,則

  • 圍繞關注節點 a 的祖父節點 c 右旋;
  • 將關注節點 a 的父節點 b、兄弟節點 c 的顏色互換;
  • 調整結束

3、刪除操作的平衡調整

思路:根據關注節點與周圍節點的排布特點,按照一定的規則去調整來達到平衡

刪除操作的平衡調整方法:

  • 第一步,針對刪除節點初步調整。
    • 使其的每個節點,從該節點到達其可達葉子節點的所有路徑,都包含相同數目的黑色節點(紅黑樹定義中最後一條)
  • 第二步,針對關注節點進行二次調整。
    • ==》不存在相鄰的兩個紅色節點(紅黑樹定義中第三條)

(1)針對刪除節點初步調整

注1:有些節點會被標記成兩種顏色,“紅 - 黑” 或 “黑 - 黑”。若標記為“黑 - 黑”,則在計算黑色節點個數時,要算成兩個黑色節點。
注2:畫圖時:若一個節點既可以是紅色,又可以是黑色==》用一半紅色一半黑色表示;若一個節點是“紅 - 黑”或“黑 - 黑”==》在左上角用小黑點表示額外的黑色。

case1:若要刪除的節點是 a,它只有一個子節點 b,則:

  • 刪除節點a,並把節點 b 替換到節點 a 的位置;(同普通的二叉樹刪除操作一樣)
  • 節點 a 只能是黑色,節點 b 也只能是紅色,其他情況均不符合紅黑樹定義。這種情況下,將節點 b 改為黑色。。
  • 調整結束,不需要進行二次調整。
    在這裡插入圖片描述

case2:若要刪除的節點 a 有兩個非空子節點,並且它的後繼節點就是節點 a 的右子節點 c,則

  • 若節點 a 的後繼節點就是右子節點 c,那右子節點 c 肯定沒有左子樹。則把節點 a 刪除,並且將節點 c 替換到節點 a 的位置。(該部分與普通的二叉查詢樹的刪除操作相同)
  • 然後將節點 c 的顏色設定為與節點 a 相同的顏色;
  • 若節點 c 是黑色,為了不違反紅黑樹最後一條定義,將節點 c 的右子節點 d 多加一個黑色,此時節點 d 就成了“紅 - 黑”或“黑 - 黑”;
  • 此時,關注節點變成節點 d,第二步的調整就針對關注節點進行操作
    在這裡插入圖片描述

case3:若要刪除的是節點 a,有兩個非空子節點,並且節點 a 的後繼節點不是右子節點,則:

  • 找到後繼節點 d,並將其刪除,刪除後繼節點 d 的過程參考 case 1;
  • 將節點 a 替換成後繼結點 d;
  • 把節點 d 的顏色設定為與節點 a 相同的顏色;
  • 若節點 d 是黑色,將節點 d 的右子節點 c 多加一個黑色,則節點 c 變成“紅 - 黑”或“黑 - 黑”(紅黑樹定義最後一條)
  • 關注節點變成節點 c,第二步調整操作針對關注點進行調整。
    在這裡插入圖片描述

(2)針對關注節點二次調整

經過初步調整,關注節點變成了“紅 - 黑”或“黑 - 黑”節點。
二次調整的目的:紅黑樹中不存在相鄰的紅色節點
==》四種情況:

case1:若關注節點是 a,其兄弟節點 c 是紅色,則:

  • 圍繞關注節點 a 的父節點 b 左旋;
  • 關注節點 a 的父節點 b 和 祖父節點 c 交換顏色;
  • 關注節點不變;
  • 繼續從四種情況中選擇合適的規則來調整。
    在這裡插入圖片描述

case2:若關注節點是 a,其兄弟節點 c 是黑色,並且節點 c 的 左右子節點 d、e都是黑色,則:

  • 將關注節點 a 的兄弟節點 c 的顏色設定為 紅色;
  • 從關注節點 a 中去掉一個黑色==》節點 a 為單純的紅色或黑色;
  • 給關注節點 a 的父節點 b 新增一個黑色==》節點 b 變成“紅 - 黑”或者“黑 - 黑”;
  • 關注節點從 a 變成其父節點 b;
  • 繼續從四種情況中選擇符合的規則來調整。
    在這裡插入圖片描述

case3:關注節點是 a,其兄弟節點 c 是黑色,c 的左子結點 d 是紅色,c 的右子節點 e 是黑色,則:

  • 圍繞關注節點 a 的兄弟節點 c 左旋;
  • 節點 c 和節點 d 交換顏色;
  • 關注節點不變;
  • 跳轉case4,繼續調整。
    在這裡插入圖片描述

case4:若關注節點 a 的兄弟節點 c 是黑色,且 c 的右子節點是紅色,則:

  • 圍繞關注節點 a 的父節點 b 左旋;
  • 將關注節點 a 的兄弟節點 c 的顏色,跟關注節點 a 的父節點 b 設定為相同的顏色;
  • 將關注節點 a 的父節點 b 的顏色設定為黑色;
  • 從關注節點 a 中去掉一個黑色,節點 a 就變成單純的紅色或黑色;
  • 將關注節點 a 的叔叔節點 e 設定為黑色;
  • 調整結束。
    在這裡插入圖片描述

三、TIPs

  • 找準關注節點,不要搞丟、搞錯關注節點