红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和 Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
红黑树是一种很有意思的平衡检索树。它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。
点击(此处)折叠或打开
- /*
- 性质1. 节点是红色或黑色
- 性质2. 根是黑色
- 性质3. 每个红色节点的两个子节点都是黑色 (从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
- */
- #include <stdio.h>
- #include <stdlib.h>
- typedef enum Color //定义红黑树结点颜色颜色类型
- {
- RED = 0,
- BLACK = 1
- }Color;
- typedef struct Node //定义红黑树结点类型
- {
- struct Node *parent;
- struct Node *left;
- struct Node *right;
- int value;
- Color color;
- }Node, *Tree;
- Node *nil=NULL; //为了避免讨论结点的边界情况,定义一个nil结点代替所有的NULL
- Node* Parent(Node *z) //返回某结点的父母
- {
- return z->parent;
- }
- Node* Left(Node *z) //返回左子树
- {
- return z->left;
- }
- Node *Right(Node *z) //返回右子树
- {
- return z->right;
- }
- void LeftRotate(Tree &T, Node *x) //左旋转:结点x原来的右子树y旋转成为x的父母
- {
- if( x-> right != nil )
- {
- Node *y=Right(x);
- x->right=y->left;
- if(y->left != nil)
- {
- y->left->parent=x;
- }
- y->parent=x->parent;
- if( x->parent == nil )
- {
- T=y;
- }
- else
- {
- if( x == Left(Parent(x)) )
- {
- x->parent->left=y;
- }
- else
- {
- x->parent->right=y;
- }
- }
- y->left=x;
- x->parent=y;
- }
- else
- {
- printf("%s/n","can't execute left rotate due to null right child");
- }
- }
- void RightRotate(Tree &T, Node *x) //右旋转:结点x原来的左子树y旋转成为x的父母
- {
- if( x->left != nil )
- {
- Node *y=Left(x);
- x->left=y->right;
- if( y->right != nil )
- {
- y->right->parent=x;
- }
- y->parent=x->parent;
- if( x->parent == nil )
- {
- T=y;
- }
- else
- {
- if(x == Left(Parent(x)) )
- {
- x->parent->left=y;
- }
- else
- {
- x->parent->right=y;
- }
- }
- y->right=x;
- x->parent=y;
- }
- else
- {
- printf("%s/n","can't execute right rotate due to null left child");
- }
- }
- void InsertFixup(Tree &T, Node *z) //插入结点后, 要维持红黑树四条性质的不变性
- {
- Node *y;
- while( Parent(z)->color == RED ) //因为插入的结点是红色的,所以只可能违背性质3,即假如父结点也是红色的,要做调整
- {
- if( Parent(Parent(z))->left == Parent(z) ) //如果要插入的结点z是其父结点的左子树
- {
- y=Parent(Parent(z))->right; // y设置为z的叔父结点
- if( y->color == RED ) //case 1: 如果y的颜色为红色,那么将y与z的父亲同时着为黑色,然后把z的
- { //祖父变为红色,这样子z的祖父结点可能违背性质3,将z上移成z的祖父结点
- y->color=BLACK;
- z->parent->color=BLACK;
- z->parent->parent->color=RED;
- z=z->parent->parent;
- }
- else
- {
- if( z == z->parent->right ) //case 2: 如果y的颜色为黑色,并且z是z的父母的右结点,则z左旋转,并且将z变为原来z的parent.
- {
- z=z->parent;
- LeftRotate(T, z);
- }
- z->parent->color=BLACK; //case 3: 如果y的颜色为黑色,并且z是z的父母的左结点,那么将z的
- z->parent->parent->color=RED; //父亲的颜色变为黑,将z的祖父的颜色变为红,然后旋转z的祖父
- RightRotate(T,z->parent->parent);
- }
- }
- else //与前一种情况对称,要插入的结点z是其父结点的右子树,注释略去
- {
- y=Parent(Parent(z))->left;
- if( y->color == RED)
- {
- z->parent->color=BLACK;
- y->color=BLACK;
- z->parent->parent->color=RED;
- z=z->parent->parent;
- }
- else
- {
- if( z == z->parent->left )
- {
- z=z->parent;
- RightRotate(T,z);
- }
- z->parent->color=BLACK;
- z->parent->parent->color=RED;
- LeftRotate(T,z->parent->parent);
- }
- }
- }
- T->color=BLACK; //最后如果上升为T的根的话,把T的颜色设置为黑色
- }
- void Insert(Tree &T, int val) //插入结点
- {
- if(T == NULL) //初始化工作:如果根尚不存在,那么new一个新结点给根,同时new一个新结点给nil
- {
- T=(Tree)malloc(sizeof(Node));
- nil=(Node*)malloc(sizeof(Node));
- nil->color=BLACK; //nil的颜色设置为黑
- T->left=nil;
- T->right=nil;
- T->parent=nil;
- T->value=val;
- T->color=BLACK; //为了满足性质2,根的颜色设置为黑色
- }
- else //如果此树已经不为空,那么从根开始,从上往下查找插入点
- {
- Node *x=T; //用x保存当前顶点的父母结点,用p保存当前的结点
- Node *p=nil;
- while(x != nil) //如果val小于当前结点的value值,则从左边下去,否则从右边下去
- {
- p=x;
- if(val < x->value )
- {
- x=x->left;
- }
- else if(val > x->value)
- {
- x=x->right;
- }
- else
- {
- printf("%s %d/n","duplicate value",val); //如果查找到与val值相同的结点,则什么也不做,直接返回
- return;
- }
- }
- x=(Node*)malloc(sizeof(Node));
- x->color=RED; //新插入的结点颜色设置为红色
- x->left=nil;
- x->right=nil;
- x->parent=p;
- x->value=val;
- if( val < p->value )
- {
- p->left = x;
- }
- else
- {
- p->right = x;
- }
- InsertFixup(T, x); //插入后对树进行调整
- }
- }
- Node* Successor(Tree &T, Node *x) //寻找结点x的中序后继
- {
- if( x->right != nil ) //如果x的右子树不为空,那么为右子树中最左边的结点
- {
- Node *q=nil;
- Node *p=x->right;
- while( p->left != nil )
- {
- q=p;
- p=p->left;
- }
- return q;
- }
- else //如果x的右子树为空,那么x的后继为x的所有祖先中为左子树的祖先
- {
- Node *y=x->parent;
- while( y != nil && x == y->right )
- {
- x=y;
- y=y->parent;
- }
- return y;
- }
- }
- void DeleteFixup(Tree &T, Node *x) //删除黑色结点后,导致黑色缺失,违背性质4,故对树进行调整
- {
- while( x != T && x->color == BLACK ) //如果x是红色,则直接把x变为黑色跳出循环,这样子刚好补了一重黑色,也满足了性质4
- {
- if( x == x->parent->left ) //如果x是其父结点的左子树
- {
- Node *w=x->parent->right; //设w是x的兄弟结点
- if( w->color == RED ) //case 1: 如果w的颜色为红色的话
- {
- w->color=BLACK;
- x->parent->color=RED;
- LeftRotate(T, x->parent);
- w=x->parent->right;
- }
- if( w->left->color == BLACK && w->right->color == BLACK ) //case 2: w的颜色为黑色,其左右子树的颜色都为黑色
- {
- w->color=RED;
- x=x->parent;
- }
- else if( w->right->color == BLACK ) //case 3: w的左子树是红色,右子树是黑色的话
- {
- w->color=RED;
- w->left->color=BLACK;
- RightRotate(T, w);
- w=x->parent->right;
- }
- w->color=x->parent->color; //case 4: w的右子树是红色
- x->parent->color=BLACK;
- w->right->color=BLACK;
- LeftRotate(T , x->parent);
- x=T;
- }
- else //对称情况,如果x是其父结点的右子树
- {
- Node *w=x->parent->left;
- if( w->color == RED )
- {
- w->color=BLACK;
- x->parent->color=RED;
- RightRotate(T, x->parent);
- w=x->parent->left;
- }
- if( w->left->color == BLACK && w->right->color == BLACK )
- {
- w->color=RED;
- x=x->parent;
- }
- else if( w->left->color == BLACK )
- {
- w->color=RED;
- w->right->color=BLACK;
- LeftRotate(T, w);
- w=x->parent->left;
- }
- w->color=x->parent->color;
- x->parent->color=BLACK;
- w->left->color=BLACK;
- RightRotate(T , x->parent);
- x=T;
- }
- }
- x->color=BLACK;
- }
- void Delete(Tree &T, Node *z) //在红黑树T中删除结点z
- {
- Node *y; //y指向将要被删除的结点
- Node *x; //x指向将要被删除的结点的唯一儿子
- if( z->left == nil || z->right == nil ) //如果z有一个子树为空的话,那么将直接删除z,即y指向z
- {
- y=z;
- }
- else
- {
- y=Successor(T, z); //如果z的左右子树皆不为空的话,则寻找z的中序后继y,
- } //用其值代替z的值,然后将y删除 ( 注意: y肯定是没有左子树的 )
- if( y->left != nil ) //如果y的左子树不为空,则x指向y的左子树
- {
- x=y->left;
- }
- else
- {
- x=y->right;
- }
- x->parent=y->parent; //将原来y的父母设为x的父母,y即将被删除
- if( y->parent == nil )
- {
- T=x;
- }
- else
- {
- if( y == y->parent->left )
- {
- y->parent->left=x;
- }
- else
- {
- y->parent->right=x;
- }
- }
- if( y != z ) //如果被删除的结点y不是原来将要删除的结点z,
- { //即只是用y的值来代替z的值,然后变相删除y以达到删除z的效果
- z->value=y->value;
- }
- if( y->color == BLACK ) //如果被删除的结点y的颜色为黑色,那么可能会导致树违背性质4,导致某条路径上少了一个黑色
- {
- DeleteFixup(T, x);
- }
- }
- Node* Search(Tree T, int val)
- {
- if( T != nil )
- {
- if( val < T->value )
- {
- Search(T->left, val);
- }
- else if ( val > T->value )
- {
- Search(T->right,val);
- }
- else
- {
- return T;
- }
- }
- }
- void MidTranverse(Tree T)
- {
- if( T != NULL && T != nil )
- {
- MidTranverse(T->left);
- printf("%d ",T->value);
- MidTranverse(T->right);
- }
- }
- int main()
- {
- Tree t=NULL;
- Insert(t,30);
- Insert(t,50);
- Insert(t,65);
- Insert(t,80);
- Delete(t,Search(t,30));
- Delete(t,Search(t,65));
- MidTranverse(t);
- return 0;
- }
参考文献:
1,http://blog.csdn.net/fantasywindy/article/details/5752434
2,http://www.linuxidc.com/Linux/2011-07/39027.htm
3,http://blog.chinaunix.net/uid-28458801-id-4043737.html
相关推荐
实验1:实现红黑树的基本算法, 对n的取值分别为 12、24、36、48、60,随机生成n 个互异的正整数(K1, K2, K3, ……, Kn)作为节点的关键字,向一棵初始空的红黑树中依次插入这n 个节点,统计算法运行所需时间 ,画...
根据给定的信息,本文将详细解释红黑树的C语言实现方法,并重点解析代码中涉及的关键概念和技术要点。 ### 红黑树简介 红黑树是一种自平衡二叉查找树,它通过确保树在任何操作后都能保持平衡来提供高效的查找、...
学习并理解这个C语言实现的红黑树可以帮助我们深入理解数据结构和算法,特别是对于操作系统和高性能应用开发的人员来说,掌握红黑树的原理和实现是至关重要的。此外,通过阅读和分析源代码,我们可以了解如何在实际...
红黑树的C语言实现,可以正常编译运行
7. **C语言实现**: - 在C语言中实现红黑树需要定义一个结构体来表示节点,包括键值、颜色、子节点指针等成员。同时,需要定义插入、删除、查找等操作的函数,每个函数都要考虑如何维护红黑树的性质。 通过理解并...
红黑树是一种自平衡二叉...总结来说,红黑树的C语言实现涉及了数据结构、算法、内存管理和多线程同步等多个方面。理解并实现红黑树需要扎实的计算机科学基础,但一旦掌握,它将为高效的数据存储和检索提供强大支持。
总之,红黑树的C语言实现涉及到对数据结构的理解、颜色规则的维护和自平衡操作的实现。通过掌握这些知识,我们可以创建一个高效、稳定的动态数据结构,适用于各种需要快速查找、插入和删除操作的应用场景。
本实验探讨了两种常见的自平衡二叉查找树——红黑树(Red-Black Tree)和二叉搜索树(Binary Search Tree),并用C语言实现了这两种数据结构,同时进行了性能比较。 首先,我们要理解二叉搜索树的基本特性。二叉...
在这个C语言实现的版本中,我们将深入探讨红黑树的基本操作,包括插入节点、删除节点、查询最大最小值以及找到特定节点的前驱和后继。 1. **红黑树的性质** - 每个节点都带有颜色属性,可以是红色或黑色。 - 根...
红黑树是一种自平衡二叉查找树,由Rudolf Bayer在1972年提出,它的设计目标是在保持查询效率的同时,通过特定的规则...理解并熟练掌握红黑树的原理和C语言实现,对于提升编程技能和解决复杂问题的能力具有重要意义。
本篇文章将深入探讨红黑树的基本概念、特性、以及C语言实现的关键点。 **红黑树的性质** 1. **每个节点都带有颜色属性,要么是红色要么是黑色。** 2. **根节点是黑色。** 3. **所有叶子节点(NIL或空节点)都是...
### 红黑树——C语言实现 #### 红黑树简介 红黑树(Red-Black Tree)是一种自平衡二叉查找树,在计算机科学领域有着广泛的应用,尤其是在实现关联数组方面。作为一种高效的查找、插入与删除操作的数据结构,红黑树...
红黑树的C语言实现,附加了顺序统计域,思想源自《算法导论》第三版ch13伪代码,基于的具体问题为:学校举办了一个在线ACM比赛,快速实现榜单的插入、删除、第k小查询
用C语言写的红黑树,实现了增删改查, 程序一开始初始化了给定好的红黑树,并且用颜色形象的表示,所以分比较高。提示,需要用WINTC编译,因为用到了一个库函数上颜色,想用VC编译的童鞋,可以根据代码更改。核心...
封装了linux 内核 红黑树,纯C语言,外层已经封装好了,直接使用,有压力测试,很不错
C语言实现红黑树时,首先需要定义一个节点结构体,包含元素值、颜色、左子节点、右子节点和父节点等字段。例如: ```c typedef enum {RED, BLACK} color_t; typedef struct node { int key; color_t color; ...
下面我们将详细讨论如何用C语言实现红黑树,以及涉及到的关键知识点。 首先,红黑树需要遵循以下五条性质: 1. 每个节点要么是红色,要么是黑色。 2. 根节点是黑色。 3. 所有叶子节点(NIL或空节点)是黑色。 4. ...
红黑树的c实现源码与剖析 原作者:那谁 源码剖析作者:July ===================== July说明: 由于原来的程序没有任何一行注释,我把它深入剖析,并一行一行的添加了注释, 详情请参见此文: 教你彻底实现红黑树:...
在C语言中实现平衡树,通常会涉及到AVL树、红黑树或者Treap等经典的数据结构。 **AVL树** AVL树是最先被提出的自平衡二叉搜索树,由G. M. Adelson-Velsky和E. M. Landis于1962年提出,因此得名。AVL树的关键特性是...
红黑树是一种自平衡二叉查找树,由Rudolf Bayer在1972年提出。它的设计目标是在保持二叉查找树基本性质的同时,通过引入颜色属性来保证...通过阅读书中的代码和实践,可以深入理解红黑树的工作原理及其C语言实现细节。