红黑树入门

    红黑树 (参看《算法导论》)

  红黑树是一种平衡二叉树,巧妙地利用结点颜色来简化维护平衡的难度。具有如下性质:

  1.红黑树上所有结点要么是红色的,要么是黑色的。

  2.红黑树的根节点是黑色的。

  3.如果一个结点是红色的,那么他的两个子结点必须是黑色的。

  4.对于每一个结点,他左子树的黑色结点数量必然等于右子树的黑色结点数量。

  5.所有叶子结点必然是黑色的。

  (一)抛弃原有的NULL,所有指向NULL的指针,改为指向一个与普通结点相同的T.null结点,T.null结点颜色固定为黑色,这样便解决了叶子结点的问题,同时根结点的父指针也指向它。

  (二)每次新插入结点为红色,这样不影响性质1、4、5,也就是说当插入结点时,只可能影响到性质2或者3,维护起来方便,可以向上维护,(插入结点设为x),如果x为根结点,那么可以直接改成黑色,如果不是,那么判断父结点是不是红色,如果是,说明违背了性质4,可以通过旋转、上升矛盾(直至根)来解决。

  (三)删除一个结点,寻找替代的结点,也就是后继,将这个替代点改成与原要删除的点一样的颜色,这么,问题就缩小到替代点原位置可能少了一个黑结点,那么可以通过上升矛盾子树(即令与他相对应的兄弟子树也少一个黑结点,那么便变成父结点所在的子树少了一个黑结点)或者红转黑来解决,需要注意的是不要在维护过程中,违背更多的红黑树性质。

  

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4
  5 #define RED 0
  6 #define BLACK 1
  7
  8 typedef struct node
  9 {
 10   bool color;   //结点颜色,红色或者黑色
 11   int data;     //数据存放
 12   struct node *fa,*lchild,*rchild; //三个指针
 13 }RB_Node;
 14
 15 typedef struct
 16 {
 17   RB_Node *root; //指向树的根节点
 18   RB_Node *null; //在红黑树中用来代替NULL,方便编程
 19 }Tree;
 20
 21 Tree *Tree_Init()
 22 {
 23   Tree *T;
 24   T=(Tree *)malloc(sizeof(Tree));
 25   T->null=(RB_Node *)malloc(sizeof(RB_Node));
 26   T->null->color=BLACK;
 27   T->null->lchild=T->null;
 28   T->null->rchild=T->null;
 29   T->null->fa=T->null;
 30   T->root=T->null;
 31   return T;
 32 }
 33
 34 RB_Node *Node_Init(Tree *T)
 35 {
 36   RB_Node *s;
 37   s=(RB_Node *)malloc(sizeof(RB_Node));
 38   s->color=RED;
 39   s->lchild=T->null;
 40   s->rchild=T->null;
 41   s->fa=T->null;
 42   return s;
 43 }
 44
 45 void RB_Left_Rotate(Tree *T,RB_Node *x) //左旋转,原本为 \ (x在上),旋转为 /(x在下)
 46 {
 47   RB_Node *y=x->rchild;
 48   x->rchild=y->lchild;
 49   y->lchild->fa=x;
 50   if(x==T->root) T->root=y;
 51   else
 52   {
 53     if(x==x->fa->lchild) x->fa->lchild=y;
 54     else x->fa->rchild=y;
 55   }
 56   y->fa=x->fa;
 57   y->lchild=x;
 58   x->fa=y;
 59 }
 60
 61 void RB_Right_Rotate(Tree *T,RB_Node *x) //右旋转,原本为 / (x在上),旋转为 \(x在下)
 62 {
 63   RB_Node *y=x->lchild;
 64   x->lchild=y->rchild;
 65   y->rchild->fa=x;
 66   if(x==T->root) T->root=y;
 67   else
 68   {
 69     if(x==x->fa->lchild) x->fa->lchild=y;
 70     else x->fa->rchild=y;
 71   }
 72   y->fa=x->fa;
 73   y->rchild=x;
 74   x->fa=y;
 75 }
 76
 77 void RB_Adjust_Insert(Tree *T,RB_Node *x)
 78 {
 79   while(x->fa->color==RED)
 80   {
 81     if(x->fa==x->fa->fa->lchild)
 82     {
 83       RB_Node *y=x->fa->fa->rchild;
 84       if(y->color==RED)
 85       {
 86         y->color=BLACK;
 87         x->fa->color=BLACK;
 88         x->fa->fa->color=RED;
 89         x=x->fa->fa;
 90       }
 91       else if(x==x->fa->rchild)
 92       {
 93         x=x->fa;
 94         RB_Left_Rotate(T,x);
 95       }
 96       else
 97       {
 98         x->fa->fa->color=RED;
 99         x->fa->color=BLACK;
100         RB_Right_Rotate(T,x->fa->fa);
101       }
102     }
103     else
104     {
105       RB_Node *y=x->fa->fa->lchild;
106       if(y->color==RED)
107       {
108         y->color=BLACK;
109         x->fa->color=BLACK;
110         x->fa->fa->color=RED;
111         x=x->fa->fa;
112       }
113       else if(x==x->fa->lchild)
114       {
115         x=x->fa;
116         RB_Right_Rotate(T,x);
117       }
118       else
119       {
120         x->fa->fa->color=RED;
121         x->fa->color=BLACK;
122         RB_Left_Rotate(T,x->fa->fa);
123       }
124     }
125   }
126   T->root->color=BLACK;
127 }
128
129 void RB_Insert(Tree *T,RB_Node *x)
130 {
131   //新插入结点显红色,可以在函数外面写
132   RB_Node *p=T->root,*q;
133   if(p==T->null)
134   {
135     T->root=x;
136     x->color=BLACK;
137     return ;
138   }
139   while(p!=T->null)
140   {
141     q=p;
142     if(x->data>=p->data) p=p->rchild;
143     else p=p->lchild;
144   }
145   if(x->data>=q->data) q->rchild=x;
146   else q->lchild=x;
147   x->fa=q;
148   RB_Adjust_Insert(T,x);
149 }
150
151 RB_Node *RB_Search_MinMum(Tree *T,RB_Node *x)
152 {
153   while(x->lchild!=T->null)
154   {
155     x=x->lchild;
156   }
157   return x;
158 }
159
160 void RB_Transplant(Tree *T,RB_Node *u,RB_Node *v)
161 {
162   if(u->fa==T->null) T->root=v;
163   else if(u->fa->lchild==u) u->fa->lchild=v;
164   else u->fa->rchild=v;
165   v->fa=u->fa;
166 }
167
168 void RB_Adjust_Delete(Tree *T,RB_Node *x)
169 {
170   while(x!=T->root&&x->color==BLACK)
171   {
172     if(x==x->fa->lchild)
173     {
174       RB_Node *w=x->fa->rchild;
175       if(w->color==RED)
176       {
177         w->color=BLACK;
178         x->fa->color=RED;
179         RB_Left_Rotate(T,x->fa);
180         w=x->fa->rchild;
181       }
182       else if(w->lchild->color==BLACK&&w->rchild->color==BLACK)
183       {
184         w->color==RED;
185         x=x->fa;
186       }
187       else if(w->rchild->color==BLACK)
188       {
189         w->lchild->color=BLACK;
190         w->color=RED;
191         RB_Right_Rotate(T,w);
192         w=x->fa->rchild;
193       }
194       else
195       {
196         w->color=x->fa->color;
197         x->fa->color=BLACK;
198         w->rchild->color=BLACK;
199         RB_Left_Rotate(T,x->fa);
200         x=T->root;
201       }
202     }
203     else
204     {
205       RB_Node *w=x->fa->lchild;
206       if(w->color==RED)
207       {
208         w->color=BLACK;
209         x->fa->color=RED;
210         RB_Right_Rotate(T,x->fa);
211         w=x->fa->lchild;
212       }
213       else if(w->lchild->color==BLACK&&w->rchild->color==BLACK)
214       {
215         w->color=RED;
216         x=x->fa;
217       }
218       else if(w->lchild->color==BLACK)
219       {
220         w->rchild->color=BLACK;
221         w->color=RED;
222         RB_Left_Rotate(T,w);
223         w=x->fa->lchild;
224       }
225       else
226       {
227         w->color=x->fa->color;
228         x->fa->color=BLACK;
229         w->lchild->color=BLACK;
230         RB_Right_Rotate(T,x->fa);
231         x=T->root;
232       }
233     }
234   }
235   x->color=BLACK;
236 }
237
238 void RB_Delete(Tree *T,RB_Node *z)
239 {
240   RB_Node *y=z,*x;
241   bool y_original_color=y->color;
242   if(z->lchild==T->null)
243   {
244     x=z->rchild;
245     RB_Transplant(T,z,z->rchild);
246     free(z);
247   }
248   else if(z->rchild==T->null)
249   {
250     x=z->lchild;
251     RB_Transplant(T,z,z->lchild);
252     free(z);
253   }
254   else
255   {
256     y=RB_Search_MinMum(T,z->rchild);
257     y_original_color=y->color;
258     x=y->rchild;
259     if(y->fa==z)
260       x->fa=y;  //等会要从x处开始调整,如果x为T->null,那么现在先预置T->null的父结点为y
261     else
262     {
263       RB_Transplant(T,y,y->rchild);
264       y->rchild=z->rchild;
265       y->rchild->fa=y; //也有上面x->fa=y;的效果
266     }
267     RB_Transplant(T,z,y);
268     y->lchild=z->lchild;
269     y->lchild->fa=y;
270     y->color=z->color;
271     free(z);
272   }
273   if(y_original_color==BLACK)
274     RB_Adjust_Delete(T,x);
275 }
276
277 void RB_Display_Tree(Tree *T,RB_Node *p,int floor=0)
278 {
279   if(p==T->null) return;
280   RB_Display_Tree(T,p->lchild,floor+1);
281   for(int i=0;i<floor;i++)
282     printf(" ");
283   printf("%d %s\n",p->data,p->color==BLACK?"BLACK":"RED");
284   RB_Display_Tree(T,p->rchild,floor+1);
285 }
286
287 RB_Node *RB_Search(Tree *T,int data)      //找到第一个,如果没有,返回T->null
288 {
289   RB_Node *p=T->root;
290   while(p!=T->null)
291   {
292     if(p->data==data) return p;
293     if(data>p->data) p=p->rchild;
294     else p=p->lchild;
295   }
296   return T->null;
297 }
298
299 void RB_Clear(Tree *T,RB_Node *x)
300 {
301   if(x!=T->null)
302   {
303     RB_Clear(T,x->lchild);
304     RB_Clear(T,x->rchild);
305     free(x);
306   }
307 }
308
309 void CE_SHI()   //用于测试红黑树
310 {
311   Tree *T;
312   T=Tree_Init();
313   while(1)
314   {
315     printf("\n--------红黑树---------------\n");
316     printf("1. 添加结点\n");
317     printf("2. 删除结点\n");
318     printf("0. 退出\n");
319     int ch;
320     scanf("%d",&ch);
321     if(ch==1)
322     {
323       printf("请输入关键字:");
324       scanf("%d",&ch);
325       RB_Node *x;
326       x=Node_Init(T);
327       x->data=ch;
328       RB_Insert(T,x);
329       RB_Display_Tree(T,T->root);
330     }
331     else if(ch==2)
332     {
333       printf("请输入关键字:");
334       scanf("%d",&ch);
335       RB_Node *x=RB_Search(T,ch);
336       RB_Delete(T,x);
337       RB_Display_Tree(T,T->root);
338     }
339     else if(ch==0)
340     {
341       RB_Clear(T,T->root);
342       T->root=T->null;
343     }
344     system("pause");
345     system("cls");
346     RB_Display_Tree(T,T->root);
347   }
348   free(T);
349 }
350
351 int main()
352 {
353   CE_SHI();
354   return 0;
355 }
时间: 2024-12-23 16:29:54

红黑树入门的相关文章

【C/C++学院】0828-STL入门与简介/STL容器概念/容器迭代器仿函数算法STL概念例子/栈队列双端队列优先队列/数据结构堆的概念/红黑树容器

STL入门与简介 #include<iostream> #include <vector>//容器 #include<array>//数组 #include <algorithm>//算法 using namespace std; //实现一个类模板,专门实现打印的功能 template<class T> //类模板实现了方法 class myvectorprint { public: void operator ()(const T &

手撸红黑树-Red-Black Tree 入门

一.学习红黑树前的准备: 熟悉基础数据结构 了解二叉树概念 二.红黑树的规则和规则分析: 根节点是黑色的 所有叶子节点(Null)是黑色的,一般会认定节点下空节点全部为黑色 如果节点为红色,那么子节点全部为黑色 从某一节点出发,到达叶子节点的所有分支上,黑色节点的数量相同 由规则4引出的一个定义,从根节点到叶子节点的黑色节点数量成为 树的黑色高度.我们会发现由于红色节点下全部为黑色节点,那么最极端的情况就是,根节点出发,左子树全部为黑色节点,右子树为红色-黑色轮换,这样设想下不难发现,树的最长路

通过2-3树理解红黑树

一.简介 前面的文章我们循序渐进的讲解了<二叉树><二分搜索树><AVL-平衡二叉树>,从左至右互为基础.尤其是二分搜索树给了我们如何将数据组织成为搜索树的思想,当然二分搜索树存在的天然问题--在极端情况下回退化为链表.所以引出了AVL-平衡二叉树,通过再平衡即LL,LR,RR,RL四个旋转操作维护了一棵平衡的二分搜索树.本章节我们继续梳理一个高阶的树结构即:红黑树.想必大家都知道,红黑树如何维持平衡,如何进行颜色反转让人很难理解,虽然很多博文很多书对红黑树都有讲解,但

B树、B+树、红黑树、AVL树比较

B树是为了提高磁盘或外部存储设备查找效率而产生的一种多路平衡查找树. B+树为B树的变形结构,用于大多数数据库或文件系统的存储而设计. B树相对于红黑树的区别 在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况.为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写.磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读

红黑树之删除节点

红黑树之删除节点 上一篇文章中讲了如何向红黑树中添加节点,也顺便创建了一棵红黑树.今天写写怎样从红黑树中删除节点. 相比于添加节点,删除节点要复杂的多.不过我们慢慢梳理,还是能够弄明白的. 回顾一下红黑树的性质 红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色.在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 节点是红色或黑色. 根节点是黑色. 每个叶节点(这里的叶节点是指NULL节点,在<算法导论>中这个节点叫哨兵节点,除了颜色属性外,其他属性值都为任

数据结构与算法-红黑树

前言 红黑树是工程中最常用到的一种自平衡二叉排序树,其和AVL树类似,都是在进行插入.删除时通过一定的调整操作来维持相对稳定的树高,从而获得较好的查询性能. 性质 1. 节点是红色或黑色. 2. 根节点是黑色. 3 每个叶节点(null节点)是黑色的. 4 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) 5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点. 维护红黑树形状(树高)的,主要就是4.5两条性质,性质4决定了最长的路径莫过于红黑间隔

数据结构学习笔记-排序/队/栈/链/堆/查找树/红黑树

排序: 插入排序:每次从剩余数据中选取一个最小的,插入已经排序完成的序列中 合并排序:将数据分成左右两组分别排序,然后合并,对每组数据的排序递归处理. 冒泡排序:重复交换两个相邻元素,从a[1]开始向a[0]方向冒泡,然后a[2]...当a[i]无法继续往前挤的时候说明前面的更小了,而且越往前越小(挤得越往前) 堆排序:构造最大堆,每次取走根结点(自然是最大的),再调用MAX-HEAPIFY算法(见后文的堆)恢复最大堆的性质,重复取走根结点 快速排序(对A[r]-A[n]进行排序): 1.从序列

红黑树与AVL(平衡二叉树)的区别

关于红黑树和AVL树,来自网络: 1 好处 及 用途 红黑树 并不追求"完全平衡 "--它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能. 红黑树能够以 O(log2  n)  的时间复杂度进行搜索.插入.删除操作.此外,由于它的设计,任何不平衡都会在三次旋转之内解决.当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较"便宜"的解决方案.红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高

数据结构-红黑树

转自:http://dongxicheng.org/structure/red-black-tree/ 1. 简介 红黑树是一种自平衡二叉查找树.它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用.在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持).它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它