红黑树

 
  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 }

 

 

首先了解红黑树特性:

  1. 根节点必须为黑
  2. 节点不是红就是黑
  3. 叶子结点必须是黑,也就是nil,其实无所谓
  4. 两个红不能互为父子节点
  5. 每条从根节点到叶子结点的路径包含的黑节点数目,都是相同的(插入的算法决定的)

插入节点的步骤:

  1. 插入节点首先上色为红色,因为红色好调整
  2. 按二叉排序树找到插入位置后,开始调整

插入的调整:

 

情形1:

父节点与叔节点都为红,由此推断祖父必须为黑,只需要将祖父变红,父亲和叔叔变黑即可,以祖父节点为当前节点递归

 

情形2,默认父节点为红,叔节点为黑或者为nil:

2.1:当前节点作为左子树,父节点作为右子树,也就是>型

处理方法:父节点右旋,变成 \ 型

2.2:当前节点作为右子树,父节点作为左子树,也就是<型

处理方法:父节点左旋,变成 / 型

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这两条路径需要和原来保持一致的黑色数,变色和旋转也是很好推导的

 

 

下面的图是上面几种情况的可视化总结 

 

 

 

附上参考网络

https://segmentfault.com/a/1190000012728513

posted @ 2019-03-04 17:04  仙7道  阅读(227)  评论(0)    收藏  举报