一,紅黑樹性質。
由於二叉查找樹知道,一個高度爲h的二叉查找樹可以實現任何一種基本的動態幾何操作,如search,insert,minimum,delete,successor等操作,其時間都是O(h),這樣樹的高度低了就會執行的比較快,但是當樹的高度較高時,操作的性能可能不比鏈表好。紅黑樹是許多“平衡的”查找樹中的一種,他能保證在最壞的情況下,基本的動態集合操作的時間爲O(lgn)。
二、紅黑樹旋轉。
left-rotate(T, x)
y = right[x]
right[x] = left[y] // y的左子樹變爲x的右子樹
parent[left[y]] = x
parent[y] = parent[x] // x的父親節點是y的父親節點
if parent[y] == null
then root[T] = y // x的根節點是根節點則置爲y
else if x == left[parent[x]] // 如果x是其父節點的左孩子節點,則將y置爲x父節點的左孩子節點否則置爲其父節點的右孩子節點
then left[parent[x]] = y
else right[parent[x]] = y
left[y] = x // y的左孩子結點是x
parent[x] = y // x的父親節點是y
三、紅黑樹插入。
rb-insert(T, z)
y = null
x = root[T]
while x != null
do y = x
if(key[x] < key[z])
then x = right[x]
else x = left[x]
parent[z] = y
if(y == null) //樹是空的
then root[T] = z
else if key[z] < key[y]
then left[y] = z
else right[y] = z
left[z] = nil[T]
right[z] = nil[T]
color[z] = RED // 着色爲紅色
rb-insert-fixup(T, z)
rb-insert-fixup(T, z)
while color[p[z]] = RED
do if parent[z] == left[parent[parent[z]]] // z節點的父親節點是其祖父節點的左孩子節點
then y = right[parent[parent[z]]] // y爲z節點的祖父節點的右孩子節點,即叔叔節點
if color[y] == RED // 叔叔節點爲紅色 CASE1
then color[parent[z]] = black // 父親節點黑色
color [y] = black // 叔叔節點黑色
color[parent[parent[z]] = red // 祖父節點紅色
z = parent[parent[z]]
esle if z == right[parent[z]] // 叔叔節點是黑的,且z爲父節點的右孩子節點 CASE2
then z = parent[z]
left-rotate(T, z) // 左旋轉
// CASE3
color[parent[z]] = black //把父節點着黑色
color[parent[parent[z]]] = red //原來的祖節點着紅色
right-rotate(T, z)
else // z節點的父親節點是其祖父節點的右孩子節點
操作和左孩子節點一樣
color[root[T]] = black // 最後把根節點置爲黑色
根據Z的父節點是Z的祖節點的左子節點還是右子節點,分爲兩組對稱的情況,每組有3種情況。以Z的父節點是Z祖節點的左子節點爲例:
第一種:Z的“叔父”節點是紅色。
如上圖所示,在這種情況下,將父、叔節點都着爲黑色,再將子樹根節點着爲紅色,那麼子樹的黑高度沒有發生改變,而且紅黑性質得得到了調整。此時,再將Z指向子樹的根節點,向上遞歸恢復紅黑特性。
第二種:Z的“叔父”節點是黑色的,Z的父節點的右子節點。
如上圖,將Z本身與其父節點進行一次左旋,讓Z指向原來的父節點,就可以調整爲情況三,下面看情況三。
第三種:Z的“叔父”節點是黑色的,Z的父節點的左子節點。
如上圖,將Z的父節點與祖節點進行一次右旋,並把父節點着黑色,原來的祖節點着紅色。這些子樹的紅黑特性得到了恢復,而且子樹的黑高度沒有變化。另外,由於子樹根節點已經是黑色了(這個節點不會出現父子同爲紅色的問題了),所以不必再向上遞歸了,此時整個樹的紅黑特性都已經是正確的了。
由於紅黑樹的刪除比較複雜,放在下一篇。
網上發現不錯的學習資料,分享一下:紅黑樹算法的層層剖析與逐步實現