STL 源碼分析: RB_tree 紅黑樹 (一)

前言

今天,來看看大名鼎鼎的紅黑樹。

紅黑樹的定義

啥子叫做紅黑樹?

首先,紅黑樹是一顆二分查找樹。二分查找樹的遞歸定義是,一個樹是二叉查找樹,它的左右子樹也是二叉查找樹,而且根節點的數值域大於所有左子樹子孫數值域,小於等於所有右子樹數值域。

其次,紅黑樹是一顆平衡二分查找樹。啥叫平衡二分查找樹呢?
wiki是這麼說的:
In computer science, a self-balancing (or height-balanced) binary search tree is any node-based binary search tree that automatically keeps its height (maximal number of levels below the root) small in the face of arbitrary item insertions and deletions.

平衡二叉樹,是指樹的高度是自平衡的,而且樹的高度不會因爲元素的插入、刪除而變得特別大。
我們知道,一個擁有n個節點的二叉樹,它的高度至少也是 l o g n logn 的。
如果某顆查找樹,它的高度也是 O ( l o g n ) O(logn) 的,那麼這顆查找樹就是個平衡二分查找樹。

爲了能夠控制住,查找樹的高度,我們當然不能讓樹隨便長,而應該給他加上一些約束條件讓它的高度是 O ( l o g n ) O(logn) 的,注意這裏只是要求 O ( l o g n ) O(logn) 意味着只要樹的高度漸進與節點個數的對數就可以了。

AVL樹是通過約束任意一個節點的兩顆子樹的高度差不能太大來實現整顆樹的高度是 O ( l o g n ) O(logn) 的,AVL樹因此需要維護每顆子樹的高度。

而紅黑樹則是通過對節點進行着紅色、黑色,通過顏色的某種約束來實現樹的高度爲 O ( l o g n ) O(logn) 的目的的。

具體來說,紅黑樹在二叉查找樹的基礎上還具有以下幾個約束:
A. 每個節點,只有兩個顏色。非紅即白。
B. 根節點爲黑色。
C. 不可出現父子節點同時爲紅的情況。但是可以出現父子節點同時爲黑的情況。
D. 對於紅黑樹的任一節點,從該節點出發,到達其 NIL 子孫的路徑上的黑色節點個數(節點本身除外)是相同的。這個節點的任意簡單路徑上的黑色節點個數又叫做黑高。NIL 子孫就是各個節點的NULL指針,NULL指針本身被當做黑色。

上圖就是一個紅黑樹。我們記 b h ( x ) bh(x) 表示節點x的黑高。
於是在上圖裏面, b h ( 5 ) = 1 , b h ( 10 ) = 1 , b h ( 15 ) = 2 , b h ( 30 ) = 3 , b h ( 85 ) = 1 bh(5)=1,bh(10)=1,bh(15)=2,bh(30)=3,bh(85)=1 ,注意在計算節點 x x 黑高的時候,無需考慮 x x 自身的顏色。而樹根的黑高 b h ( 30 ) = 3 bh(30)=3 又叫做整個紅黑樹的黑高。

爲啥子,通過這幾個顏色的約束就能把紅黑樹的高度限制在 O ( l o g n ) O(logn) 呢? 我們來證明一下。

紅黑樹高度爲O(logn)的證明

首先,我們證明一個結論:如果某個節點 x x 的黑高爲h,那麼以 x x 爲根的子樹至少有 2 h 1 2^h-1 個節點。
這玩意,當然得用數學歸納法證明啦。
x x 子樹只有一個節點的時候, b h ( x ) = 0 bh(x)=0 , 2 h 1 = 1 1 = 0 2^h-1=1-1=0 ,滿足條件。
假設 x x 作爲子樹,它的黑高爲h,它至少包含 2 h 1 2^h-1 個節點。
那麼 x x 的父節點所在的子樹的黑高應該 h + 1 h+1 h h 。這是爲啥呢?如果x是黑色的,那麼x的父親的黑高是h+1,如果x是紅色的,那麼x父親的黑高爲h。同時,x的兄弟的黑高也是h,(這是因爲,對於x的父親來說,從父親出發,不管是經過x也好,經過x的兄弟也好,到達nil節點的黑色節點個數都得相等)。於是以x的父節點爲根的子樹的節點個數就等於左子樹節點個數加右子樹節點個數,就至少有 2 h 1 + 2 h 1 + 1 = 2 h + 1 1 2^h-1+2^h-1 +1=2^{h+1}-1 個節點。不管父節點的黑高 b h bh 是h 還是h+1,以它爲根的子樹的節點個數都至少爲 2 h 1 + 2 h 1 + 1 = 2 h + 1 1 2^h-1+2^h-1 +1=2^{h+1}-1 ,都滿足節點個數至少爲 2 b h 1 2^{bh}-1 這個條件。

於是 如果某個節點 x x 的黑高爲h,那麼以 x x 爲根的子樹至少有 2 h 1 2^h-1 個節點 這個結論是成立的。

接着,我們證明第二個結論:如果某顆紅黑樹的黑高爲 h h ,那麼這棵樹的高度 l l 至少爲 h h ,至多爲 2 h 2h .

首先,既然黑高都爲h了,那麼樹高 l l 當然最小就只能到 h h 了,這種情況發生於整個樹全部都是黑色的情況。例如下圖,30的黑高爲2,那麼樹高當然最小爲2.
在這裏插入圖片描述
OK,爲了增加樹高,那麼就只能往每一條全部黑色的路徑上插入紅色的節點了。那麼對於一條從根到NIL的含有h個黑色節點的簡單路徑,一共形成了 h h 個插入點。能插入多少個紅色節點呢? 考慮到一條路徑上不能出現連續的紅色,於是每個插入點最多插一個紅色節點。在這裏插入圖片描述於是,在這條全黑的路徑上,全部最多隻能插入 h h 個紅色節點。
於是,我們得到 l l 最大隻能爲 2 h 2h 的上界。

現在,綜合這兩條結論。對於一個含有 n n 個節點的紅黑樹,假設它的黑高爲 b h bh ,那麼有 2 b h 1 < = n 2^{bh}-1 <=n ,於是 b h < = l o g ( n + 1 ) bh <=log(n+1) ,於是這顆樹的樹高 l l 應該有 l < = 2 l o g ( n + 1 ) l<=2*log(n+1) ,即樹高是 O ( l o g n ) O(logn) 的。

因此,只要在紅黑樹的插入、刪除過程中,保證這4條性質的成立就能保證樹的高度是 O ( l o g n ) O(logn) 的。

接下來,就看STL的實現中是如何滿足這四條性質的。