紅黑樹

 
  1 #include "MyRBTree.h"
  2 #include <iostream>
  3 
  4 
  5 
  6 MyRBTree::MyRBTree()
  7 {
  8     root_ = nullptr;
  9 }
 10 
 11 
 12 MyRBTree::~MyRBTree()
 13 {
 14 }
 15 
 16 
 17 void MyRBTree::PrePrint(RBTNode *tree)
 18 {
 19     if (tree == nullptr)
 20         return;
 21     PrePrint(tree->lchild);
 22 
 23     auto tmp = (tree->color == COLOR::RED) ? "RED" : "BLACK         ";
 24     std::cout << tmp << "___:" << tree->value << "\n";
 25 
 26     PrePrint(tree->rchild);
 27 }
 28 
 29 void MyRBTree::MidPrint(RBTNode *tree)
 30 {
 31     if (tree == nullptr)
 32         return;
 33     auto tmp = (tree->color == COLOR::RED) ? "RED" : "BLACK         ";
 34     std::cout << tmp << "___:" << tree->value<<"\n";
 35     MidPrint(tree->lchild);
 36     MidPrint(tree->rchild);
 37 }
 38 
 39 
 40 RBTNode* MyRBTree::Search(RBTNode *tree, int value)
 41 {
 42     //沒有找到
 43     if (tree == nullptr)
 44         return nullptr;
 45 
 46     if (tree->value == value)
 47         return tree;
 48 
 49     if (tree->value >= value)
 50         return Search(tree->lchild, value);
 51     else
 52         return Search(tree->rchild, value);
 53 }
 54 
 55 
 56 RBTNode *MyRBTree::FindForwardNode(RBTNode *tree)
 57 {
 58     while (tree->rchild != nullptr)
 59     {
 60         tree = tree->rchild;
 61     }
 62     return tree;
 63 }
 64 
 65 void MyRBTree::Del(int value)
 66 {
 67     //第一步,找到節點
 68     auto node = Search(root_,value);
 69     if (node == nullptr)
 70         return;
 71     
 72     bool left_side_unbalance = true;//當前節點的左(右)子樹缺乏一個黑節點
 73     RBTNode *backward_node = nullptr;
 74     if (node->lchild != nullptr) {
 75         backward_node = FindForwardNode(node->lchild);//真正的前驅,沒有右節點
 76     }
 77     else
 78         backward_node = node;//原始node,沒有左節點
 79 
 80     //交換後繼節點和當前節點value
 81     {
 82         auto tmp = node->value;
 83         node->value = backward_node->value;
 84         backward_node->value = tmp;
 85     }
 86 
 87     //開始刪除後繼節點,只有一個或者沒有子樹
 88     {
 89         bool is_red = backward_node->color == COLOR::RED;
 90         auto parent = backward_node->parent;
 91 
 92         //若是backward_node爲根節點
 93         if (parent == nullptr)
 94         {
 95             if (backward_node->lchild != nullptr)
 96             {
 97                 backward_node->lchild->parent = nullptr;
 98                 backward_node->lchild->color = COLOR::BLACK;
 99                 delete backward_node;
100                 root_ = backward_node->lchild;
101             }
102             else if (backward_node->rchild != nullptr)
103             {
104                 backward_node->rchild->parent = nullptr;
105                 backward_node->rchild->color = COLOR::BLACK;
106                 delete backward_node;
107                 root_ = backward_node->rchild;
108             }
109 
110             return;
111         }
112 
113         if (parent->lchild == backward_node)        {
114             left_side_unbalance = true;
115         }
116         else {
117             left_side_unbalance = false;
118         }
119 
120         //不存在兩個子節點都存在的狀況
121         if (backward_node->lchild != nullptr)
122         {
123             if (left_side_unbalance) {
124                 parent->lchild = backward_node->lchild;
125             }
126             else {
127                 parent->rchild = backward_node->lchild;
128             }
129             backward_node->lchild->parent = parent;
130         }
131         else if (backward_node->rchild != nullptr)
132         {
133             if (left_side_unbalance) {
134                 parent->lchild = backward_node->rchild;
135             }
136             else {
137                 parent->rchild = backward_node->rchild;
138             }
139             backward_node->rchild->parent = parent;
140         }
141         else if (backward_node->lchild == nullptr
142             &&
143             backward_node->rchild == nullptr
144             )
145         {
146             if (left_side_unbalance)
147                 parent->lchild = nullptr;
148             else
149                 parent->rchild = nullptr;
150         }
151 
152         delete backward_node;
153         //後繼節點從新指向
154         backward_node = parent;
155 
156         //若是刪除的節點爲紅色的,不影響紅黑樹屬性,完成刪除
157         if (is_red)
158             return;
159     }
160     
161     
162     DelBalance(backward_node, left_side_unbalance);
163 
164 }
165 
166 
167 void MyRBTree::DelBalance(RBTNode *forward_parent, bool left_side_unbalance)
168 {
169     auto parent = forward_parent;
170 
171     //若是backward_node爲根節點
172     if (parent == nullptr)
173     {
174         root_ = forward_parent;
175         return;
176     }
177 
178     //討論backward_node的左子樹少了一個黑節點的狀況
179     if (left_side_unbalance)
180     {
181         //node 節點到這裏已經必須是黑色的
182         auto uncle = parent->rchild;
183         auto u_l = uncle->lchild;
184         auto u_r = uncle->rchild;
185 
186         auto color_parent = parent->color;
187         auto color_uncle_parent = uncle==nullptr? COLOR::BLACK:uncle->color;
188         auto color_u_l_parent = u_l == nullptr ? COLOR::BLACK : u_l->color;
189         auto color_u_r_parent = u_r == nullptr ? COLOR::BLACK : u_r->color;
190 
191         //狀況1:全黑
192         if (color_parent == COLOR::BLACK
193             &&color_uncle_parent == COLOR::BLACK
194             &&color_u_l_parent == COLOR::BLACK
195             &&color_u_r_parent == COLOR::BLACK
196             )
197         {
198             uncle->color = COLOR::BLACK;
199             return DelBalance(parent);//遞歸parent,整顆parent樹少了一個黑節點
200         }
201 
202         //狀況2:P紅 其餘黑
203         if (color_parent == COLOR::RED
204             &&color_uncle_parent == COLOR::BLACK
205             &&color_u_l_parent == COLOR::BLACK
206             &&color_u_r_parent == COLOR::BLACK
207             )
208         {
209             uncle->color = COLOR::RED;
210             parent->color = COLOR::BLACK;
211             return;//搞定
212         }
213 
214         //狀況3:U紅 其餘黑
215         if (color_parent == COLOR::BLACK
216             &&color_uncle_parent == COLOR::RED
217             &&color_u_l_parent == COLOR::BLACK
218             &&color_u_r_parent == COLOR::BLACK
219             )
220         {
221             uncle->color = COLOR::BLACK;
222             parent->color = COLOR::RED;
223             L_Rotate(parent);
224             return DelBalance(parent,true);//遞歸當前節點
225         }
226 
227         //狀況4:UL紅 P無所謂 其餘黑
228         if (color_uncle_parent == COLOR::BLACK
229             &&color_u_l_parent == COLOR::RED
230             &&color_u_r_parent == COLOR::BLACK
231             ) {
232             uncle->color = COLOR::RED;
233             u_l->color = COLOR::BLACK;
234             R_Rotate(uncle);
235             return DelBalance(parent);//遞歸當前節點
236         }
237 
238         //狀況5:UR紅 P\UL無所謂 U黑
239         if (color_uncle_parent == COLOR::BLACK
240             &&color_u_r_parent == COLOR::RED
241             )
242         {
243             uncle->color = parent->color;
244             parent->color = COLOR::BLACK;
245             u_r->color = COLOR::BLACK;
246             L_Rotate(parent);
247             return;
248         }
249     }
250 }
251 
252 void MyRBTree::Insert(int value)
253 {
254     RBTNode *node = new RBTNode();
255     node->value = value;
256     //根節點 直接插入
257     if (root_ == nullptr)    {
258         root_ = node;
259         root_->color = COLOR::BLACK;//跟節點顏色默認爲黑
260         return;
261     }
262     else {
263         InsertNode(root_, root_,node);
264 
265         Balance(node);
266     }
267 
268 
269 }
270 
271 
272 
273 void MyRBTree::InsertNode(RBTNode*&tree, RBTNode*parent, RBTNode*node)
274 {
275     do {
276         if (tree == nullptr)
277         {
278             tree = node;
279             node->parent = parent;
280             break;
281         }
282         //插入到左子樹
283         if (tree->value >= node->value) {
284             InsertNode(tree->lchild, tree, node);
285             break;
286         }
287         //插入到右子樹
288         if (tree->value < node->value) {
289             InsertNode(tree->rchild, tree,node);
290             break;
291         }
292     } while (0);
293     
294 }
295 
296 
297 void MyRBTree::Balance(RBTNode *&node)
298 {    
299     auto parent = node->parent;
300 
301     if (parent == nullptr)
302     {
303         //說明node已是根節點,直接黑化
304         node->color = COLOR::BLACK;
305         root_ = node;
306         return;
307     }
308     if (parent->parent == nullptr)
309     {
310         //說明node->parent已是根節點,直接黑化
311         node->parent->color = COLOR::BLACK;
312         root_ = node->parent;
313         return;
314     }
315 
316     //前面兩步確保node含有父節點、祖父節點
317 
318 
319     if (node->parent->color == COLOR::BLACK)
320     {
321         //父節點顏色爲黑 無需調整
322         return;
323     }
324     else if (node->parent->color == COLOR::RED)
325     {
326         //父節點爲紅,繼續討論
327         bool node_is_L_Child = false; //當前節點是父節點的左節點
328         bool parent_L_Child = false; //父節點爲祖父節點的左孩子
329         auto parent = node->parent;
330         auto grand_pa = node->parent->parent;
331         RBTNode*uncle = nullptr;
332         if (parent == grand_pa->lchild) {
333             uncle = grand_pa->rchild;
334             parent_L_Child = true;
335         }
336         else {
337             uncle = grand_pa->lchild;
338             parent_L_Child = false;
339         }             
340 
341         if (node == parent->lchild)
342             node_is_L_Child = true;
343         else
344             node_is_L_Child = false;
345 
346         //最簡單的狀況
347         //第0種狀況:叔叔爲紅,那祖父確定是黑
348         if (uncle != nullptr && uncle->color == COLOR::RED)
349         {
350             //策略:父節點和叔節點變黑,祖父變紅,祖父做爲當前節點,遞歸此函數
351             parent->color = COLOR::BLACK;
352             uncle->color = COLOR::BLACK;
353             grand_pa->color = COLOR::RED;
354             Balance(grand_pa);
355             return;
356         }
357 
358         //如下狀況,叔叔節點必須爲黑,G點爲黑,P點爲紅,N點也爲紅.
359 
360         //<型:P點做爲G點的左孩子,N點做爲右孩子
361         //策略:以P爲當前節點,左旋
362         if (!node_is_L_Child && parent_L_Child)
363         {
364             L_Rotate(parent);
365             return Balance(parent);
366         }
367 
368         //>型:P點做爲G點的右孩子,N點做爲左孩子
369         //策略:以P爲當前節點,右旋
370         if (node_is_L_Child && !parent_L_Child)
371         {
372             R_Rotate(parent);
373             return Balance(parent);
374         }
375 
376         //   /型:P點做爲G點的左孩子,N點做爲左孩子
377         //策略:祖父節點爲當前節點,祖父節點變紅,父節點變黑. 祖父節點右旋
378         if (node_is_L_Child && parent_L_Child)
379         {
380             parent->color = COLOR::BLACK;
381             grand_pa->color = COLOR::RED;
382             R_Rotate(grand_pa);
383             return Balance(grand_pa);
384         }
385 
386         //  \型:P點做爲G點的右孩子,N點做爲右孩子
387         //策略:祖父節點爲當前節點,祖父節點變紅,父節點變黑. 祖父節點左旋
388         if (!node_is_L_Child && !parent_L_Child)
389         {
390             parent->color = COLOR::BLACK;
391             grand_pa->color = COLOR::RED;
392             L_Rotate(grand_pa);
393 
394             return Balance(grand_pa);
395         }
396     }
397     else
398     {
399         std::cout << "\nerror";
400     }
401 }
402 
403 
404 RBTNode* MyRBTree::L_Rotate(RBTNode*node) {
405 
406     RBTNode* parent = node->parent;
407     RBTNode * r_child = node->rchild;
408 
409     if (parent == nullptr)
410     {
411     }
412     else if (parent->lchild == node)
413     {
414         parent->lchild = r_child;
415     }
416     else if (parent->rchild == node)
417     {
418         parent->rchild = r_child;
419     }
420 
421     r_child->parent = parent;
422 
423     if (r_child->lchild != nullptr)
424     {
425         r_child->lchild->parent = node;
426     }
427     node->rchild = r_child->lchild;
428 
429     r_child->lchild = node;
430     node->parent = r_child;
431 
432     return node;
433 }
434 
435 //對node做右旋
436 RBTNode* MyRBTree::R_Rotate(RBTNode*node) {
437 
438     RBTNode* parent = node->parent;
439     RBTNode * l_child = node->lchild;
440 
441     if (parent == nullptr)
442     {
443     }
444     else if (parent->lchild == node)
445     {
446         parent->lchild = l_child;
447     }
448     else if (parent->rchild == node)
449     {
450         parent->rchild = l_child;
451     }
452 
453     l_child->parent = parent;
454 
455     if (l_child->rchild != nullptr)
456     {
457         l_child->rchild->parent = node;
458     }
459     node->lchild = l_child->rchild;
460 
461     l_child->rchild = node;
462     node->parent = l_child;
463 
464     return node;
465 }

 

 

首先了解紅黑樹特性:node

  1. 根節點必須爲黑
  2. 節點不是紅就是黑
  3. 葉子結點必須是黑,也就是nil,其實無所謂
  4. 兩個紅不能互爲父子節點
  5. 每條從根節點到葉子結點的路徑包含的黑節點數目,都是相同的(插入的算法決定的)

插入節點的步驟:ios

  1. 插入節點首先上色爲紅色,由於紅色好調整
  2. 按二叉排序樹找到插入位置後,開始調整

插入的調整:算法

 

情形1:ide

父節點與叔節點都爲紅,由此推斷祖父必須爲黑,只須要將祖父變紅,父親和叔叔變黑便可,以祖父節點爲當前節點遞歸函數

 

情形2,默認父節點爲紅,叔節點爲黑或者爲nil:性能

2.1:當前節點做爲左子樹,父節點做爲右子樹,也就是>型spa

處理方法:父節點右旋,變成 \ 型code

2.2:當前節點做爲右子樹,父節點做爲左子樹,也就是<型blog

處理方法:父節點左旋,變成 / 型排序

2.3:當前節點做爲右子樹,父節點做爲右子樹,也就是 \ 型

處理方法:祖父節點左旋,祖父變紅,父親變黑。

2.4:當前節點做爲左子樹,父節點做爲左子樹,也就是 / 型

處理方法:祖父節點右旋,祖父變紅,父親變黑。

 

總結:

<型和>型,都只是中間狀態,將其轉化成 \ /型,再對祖父節點操做,插入完畢。

紅黑樹與AVL的性能對比:

查找 AVL佔優

插入和刪除 紅黑樹佔優

由於紅黑樹保證插入每次都能在三次之內完成,減小了複雜度。

而紅黑樹的深度,由其特性可知,兩棵樹的深度之差,不會太多,由於黑節點數目相同,紅色節點不能相鄰,所以要是該樹的黑色路徑長度爲N,最長的路徑也不會超過2N。

 

 

紅黑樹的刪除:

步驟一:刪除的節點X分兩種狀況

  1. 刪除節點只有或者沒有子節點,這就是須要討論的重點
  2. 刪除節點有兩個子節點,這種狀況與二叉平衡樹的刪除同樣,先找到刪除節點的後繼或者前驅節點Y,交換X和Y的值,從而問題變成刪除Y節點,轉化成第一點討論的狀況
  3. 若是X節點顏色爲紅,通過前面1.2兩點,這裏討論的N節點最多隻有一個子節點,只需將N節點的子節點N頂替上來,紅黑樹性質不變
  4. 若是X節點顏色爲黑,就是步驟二討論的內容

步驟二:刪除的關鍵在於理解下面這張圖,有如下幾點須要注意:

  1. N節點爲刪除節點X的子節點,N替換了X原來的位置。因爲步驟一已經將問題簡化成,被刪除節點只有或者沒有子節點,因此X節點只有N一個子節點,若是X沒有子節點,N爲NIL節點,顏色默認爲黑色
  2. P爲N的父節點,S爲N的兄弟節點。通過P點的兩條路徑,PN&PS。PN路徑因爲刪除了X節點這個黑節點(這裏X節點通過步驟一,必須爲黑),因此PN和PS兩條路徑已經不平衡
  3. PN爲少了一個黑節點的路徑,稱之爲短路徑,另一條稱之爲兄弟路徑。後面只討論短路徑位於左側這種狀況。(短路徑位於右側的狀況,能夠經過反轉操做,也就是,左旋換成右旋,右旋變成左旋)

步驟三:如今狀況簡化爲只討論上圖,討論的範圍包括P,S,SL,SR四個節點的顏色狀況,須要分爲幾種狀況

 

狀況1:

P紅,其餘均爲黑

策略1:

PS換色(P黑化,S紅化)

結果1:恢復平衡

短路徑增長一個黑節點,兄弟路徑不變。

 

狀況2:

S紅,其餘均爲黑

策略2:

PS換色&P左旋

 結果2:

短路徑依舊存在,但轉化成狀況1,因此再進行一次換色,問題解決

 

狀況3:

全黑

策略3:

S變紅

結果3:

通過P節點的兩條路徑如今都少了一個黑節點,因此當前節點從N轉化成了P,接着繼續遞歸分析P。

 

狀況4:

SL紅(所以S黑),SR黑,P無所謂

策略4:

S與SL換色,S右旋

結果4:

PN依舊爲短路徑,可是轉化爲狀況5

 

狀況5:

SR紅(所以S黑),SL無所謂,P無所謂

策略5:

S變成P的顏色

P黑化

SR黑化

P左旋

結果5:恢復平衡

 

總結:上述狀況看似很差記憶,但能夠推理出來,下面是幫助記憶的方法。

重點在於五個節點:N  P  S  SL  SR,N的顏色必須爲黑,所以就只有四個節點的顏色須要討論

前面三種比較好記憶,要麼全黑,要麼除了P,其餘全黑,要麼除了S,其餘全黑。

剩下的是SL或者SR爲紅的狀況,稱之爲複雜狀況

第一種複雜狀況,SL爲紅,SR爲黑,那麼因爲紅黑樹特性,S必須爲黑。剩下P點無所謂

第二種複雜狀況,SR爲紅,SL無所謂,S必須爲黑,剩下P點無所謂

 

第一種複雜狀況須要轉化爲第二種,所以旋轉和變色的策略很好推導

第二種複雜狀況,能夠根據PN短路徑須要增長一個黑節點,而SL和SR這兩條路徑須要和原來保持一致的黑色數,變色和旋轉也是很好推導的

 

 

下面的圖是上面幾種狀況的可視化總結 

相關文章
相關標籤/搜索