紅黑樹的插入操作可以在o(logn)的時間內完成。開始插入節點的時候和二叉查詢樹一樣,只需要最後將插入的節點著成紅色,為了保證紅黑樹的性質,需要通過rb_insertfixup函式來調整該節點,對其重新著色並旋轉。
下面先呼叫rb_insert()函式將乙個節點插入到紅黑樹中,同樣先上偽**
rb-insert(t, z)
1 y ← nil[t]
2 x ← root[t]
3 while x ≠ nil[t]
4 do y ← x
5 if key[z] < key[x]
6 then x ← left[x]
7 else x ← right[x]
8 p[z] ← y
9 if y = nil[t]
10 then root[t] ← z
11 else if key[z] < key[y]
12 then left[y] ← z
13 else right[y] ← z
14 left[z] ← nil[t]
15 right[z] ← nil[t]
16 color[z] ← red
17 rb-insert-fixup(t, z)
接著上c++**並進行**分析
bool rb_insert(int key, int data)
//初始化插入節點,注意插入節點初始的顏色為red
rb_node *insert_node = new rb_node();
insert_node->key = key;
insert_node->data = data;
insert_node->rb_color = red;
insert_node->right = nil;
insert_node->left = nil;
//如果插入的是一顆空樹,設定root就是插入節點
if(insert_p == nil)
else//判斷插入左節點還是右節點
//修復紅黑樹的性質
rb_insertfixup(insert_node);
return true;
}
為了保證紅黑樹的結構性質,需要呼叫rb_insertfixup函式來調整剛剛插入的節點
我們考慮下,如果乙個紅色節點(下文稱用z指向它)被插入到樹中,那麼有哪些紅黑性質可能被破壞呢?只有性質2(根節點是黑色的,由於插入的可能是根節點)以及性質4(紅色節點的子節點一定是黑色節點,其父節點是紅色的),其它都不會被破壞。
如果插入的節點的父節點是黑色的,那麼不需要做任何調整,這紅黑樹是正常的。如果父節點是紅色,或插在樹根的位置,那麼就要進行調整以保證紅黑樹性質。
首先對性質4進行分析,我們知道,插入乙個新的節點,這個節點肯定會被放到樹的底部成為乙個葉節點,那麼這個紅色節點就沒有可能和自己的子節點同色(因為葉節點的子節點是nil節點,都是黑色的),如果性質4被破壞的話,肯定是z指向的節點的父節點是紅色的。因此,為了使分析和解決更加容易和清晰,我們在對樹進行調整以恢復紅黑特性時,始終使得z總是指向相鄰紅色的節點中的子節點(指標z可能會向上公升到樹的中部或根部)。基於這個做法,我們可以知道,如果是性質2被破壞了的話,也就是z指向根節點了,那麼性質4肯定就符合了(因為z的父節點是nil,黑色的),因此對性質2的恢復變得很簡單,只需要被根從紅色變為黑色即可。
現在只需要處理性質4被破壞的問題,如果性質4被破壞了,也就是說,z的父節點是紅色的,那麼,說明,z一定有祖父節點,而且是黑色的(否則插入前原樹就有問題,又或是調整時的方法不正確)。因此可以把問題放到以z的祖父節點為根節點的子樹內進行解決,這樣可以把調整的範圍最小化,而且這也是有可能的:只要不改變這子樹的黑高度,那麼就不會對樹的其它部分產生影響。我們要做的就是在這個子樹範圍內把紅黑性質調整回來。再看子樹的根是否與其父節點同為紅色,是的話,就再次用前面所說的去解決它,一直向上遞迴到紅黑性質被恢復為止。
對性質4的恢復,根據z的父節點是z的祖節點的左子節點還是右子節點,分為兩組對稱的情況,每組有3種情況。下面我們以z的父節點是z祖節點的左子節點為例:
定義叔叔的含義:即祖父節點的另外乙個子節點
情況1:z的叔叔y是紅色的
如上圖所示,在這種情況下,將父、叔節點都著為黑色,再將子樹根節點著為紅色,那麼子樹的黑高度沒有發生改變,而且紅黑性質得得到了調整。此時,再將z指向子樹的根節點,向上遞迴恢復紅黑特性。
情況2:z的叔叔y節點是黑色的,而且z是父節點的左子節點
如上圖,將z的父節點與祖節點進行一次右旋,並把父節點著黑色,原來的祖節點著紅色。這些子樹的紅黑特性得到了恢復,而且子樹的黑高度沒有變化。另外,由於子樹根節點已經是黑色了(這個節點不會出現父子同為紅色的問題了),所以不必再向上遞迴了,此時整個樹的紅黑特性都已經是正確的了。
情況3:z的叔叔y節點是黑色的,而且z是父節點的右子節點
如上圖,將z本身與其父節點進行一次左旋,讓z指向原來的父節點,就可以調整為情況2,而情況2已經得到解決。
由此紅黑樹插入後調整問題已經解決。
偽**:
1 while color[p[z]] = red
2 do if p[z] = left[p[p[z]]]
3 then y ← right[p[p[z]]]
4 if color[y] = red
5 then color[p[z]] ← black // case 1
6 color[y] ← black // case 1
7 color[p[p[z]]] ← red // case 1
8 z ← p[p[z]] // case 1
9 else if z = right[p[z]]
10 then z ← p[z] // case 2
11 left-rotate(t, z) // case 2
12 color[p[z]] ← black // case 3
13 color[p[p[z]]] ← red // case 3
14 right-rotate(t, p[p[z]]) // case 3
15 else (same as then clause
with "right" and "left" exchanged)
16 color[root[t]] ← black
rb_insertfixup c++原始碼:
void rb_insertfixup(rb_node *node)
else if(uncle->rb_color == black)
//情況2,z的叔叔y是黑色的,但z是左孩子
node->parent->rb_color = black;
node->parent->parent->rb_color = red;
rb_rightrotate(node->parent->parent);}}
else
else if (uncle->rb_color == black)
node->parent->rb_color = black;
node->parent->parent->rb_color = red;
rb_leftrotate(node->parent->parent);}}
}root->rb_color = black;
}
紅黑樹(插入)
紅黑樹的插入操作相對刪除操作比較簡單。紅黑樹要滿足 任一節點至null的任何路徑,所含黑節點數必須相同。所以,為了滿足此性質,插入節點應該為紅色。如果插入節點的父親為黑色,則不需要進行調整,若為紅色,有三種情況需要討論。1.父節點為紅色,叔節點為紅色 對於這種情況,同時改變父 叔節點顏色為黑色,並將...
紅黑樹插入
一 什麼是紅黑樹 紅黑樹 red black tree 是一種自平衡二叉查詢樹,是在電腦科學中用到的一種資料結構,典型的用途是實現關聯陣列。紅黑樹是一棵二叉搜尋樹,它在每個結點上增加了乙個儲存位來表示結點的顏色,可以是red或black。一棵紅黑樹是滿足下面紅黑性質的二叉搜尋樹 1 每乙個結點或是紅...
紅黑樹 插入
一 滿足下面幾個條件的二叉搜尋樹,稱為紅黑樹 1.任何乙個節點都被著色 紅色或是黑色。2.根節點是黑色的。3.所有的nil節點都看成黑色 nil節點是就是乙個假想的或是無實在意義的節點,所有應該指向null的指標,都看成指向了nil節點。包括葉節點的子節點指標或是根節點的父指標 4.如果乙個節點是紅...