紅黑樹筆記 紅黑樹的插入操作

2021-06-01 07:26:32 字數 4255 閱讀 6954

紅黑樹的插入操作可以在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.如果乙個節點是紅...