【数据结构】红黑树 C语言代码
连看带写花了三天,中途被指针引用搞得晕晕乎乎的。 插入和删除的调整过程没有看原理,只看了方法,直接照着写的。
看了两份资料,一份是算法导论第12-13章, 另一份是网上的资料http://blog.csdn.net/v_JULY_v/article/details/6105630
下面C代码是我根据 算法导论的伪码写的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef int DataType; typedef struct RBNode
{
RBNode *parent, *left, *right; //指向结点的父结点、左右孩子结点
DataType key; //结点数据
int color; //颜色 红(r) 或 黑(b)
}RBNode; //定义红黑树结点 RBNode Nil;
RBNode * nil = &Nil; void left_rotate( RBNode * &T, RBNode * x) //左旋 x一定不能有引用 因为如果引用后 x与y->parent就是等价的了, y->parent改变 x就会改变
{
RBNode * y;
y = x->right;
/************第一部分 y的左孩子 与 x间关联*************/
x->right = y->left; //x认右孩子
if(y->left != nil)
{
y->left->parent = x; //孩子认parent
}
/************第一部分 y的左孩子 与 x间关联 end*************/ /************第二部分 y 与 x的parent 关联*************/
y->parent = x->parent; //y认 x的parent为自己的parent //y的parent与x的地址是一样的 int isroot = ;
if(x->parent == nil) //x的parent根据自己的情况 认y为左或右孩子
{
isroot = ;
}
else if(x == x->parent->left)
{
x->parent->left = y;
}
else
{
x->parent->right = y;
}
/************第二部分 y 与 x的parent 关联 end*************/ /************第部分 x 与 y的关联 *************/
y->left = x; //y认x为孩子
x->parent = y; //x认y为parent
/************第部分 x 与 y的关联 end*************/
if(isroot == )
{
T = y;
}
} void right_rotate(RBNode * &T, RBNode * x) //右旋
{
RBNode * y;
y = x->left; x->left = y->right; if(y->right != nil)
{
y->right->parent = x;
} y->parent = x->parent;
int isroot = ;
if(x->parent == nil)
{
isroot = ;
}
else if(x == x->parent->right)
{
x->parent->right = y;
}
else
{
x->parent->left = y;
} y->right = x;
x->parent = y; if(isroot == )
{
T = y;
}
} void rb_insert_fixup(RBNode * &T, RBNode * z) //红黑树插入后的调整 注意z不能要引用 因为调整的过程中z的值作为位置标记会改变 但我们不希望树的结构因为z而变化
{ RBNode * y;
while(z->parent->color == 'r')
{
if(z->parent == z->parent->parent->left) //z的parent是左子的情况
{
//copy(z->parent->parent->right, y);
y = z->parent->parent->right;
if(y->color == 'r') //情况1 z的parent和uncle都是红色 把这两个红色染成黑色 把grandparent染成红色 令z = grandparent 再次循环
{
y->color = 'b';
z->parent->color = 'b';
z->parent->parent->color = 'r';
z = z->parent->parent;
}
else if(z == z->parent->right) //当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子 对策:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。
{
z = z->parent;
left_rotate(T, z);
}
else //当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子 解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
{
z->parent->color = 'b';
z->parent->parent->color = 'r';
right_rotate(T, z->parent->parent);
}
}
else //z的parent是右子的情况
{
y = z->parent->parent->left;
if(y->color == 'r')
{
z->parent->color = 'b';
y->color = 'b';
z->parent->parent->color = 'r';
z = z->parent->parent;
}
else if(z == z->parent->left)
{
z = z->parent;
right_rotate(T, z);
}
else
{
z->parent->color = 'b';
z->parent->parent->color = 'r';
left_rotate(T, z->parent->parent);
}
}
} if(z->parent == nil)
{
z->color = 'b';
return;
}
else
{
return;
}
} void rb_insert(RBNode * &T, RBNode * z) //红黑树 插入工作 注意 z不要有引用
{
RBNode * y = nil;
RBNode * x = T;
while(x != nil) //找到z适当的插入位置
{
y = x;
if(z->key < x->key)
x = x->left;
else
x = x->right;
} z->parent = y;
if(y == nil) //parent 认孩子总是麻烦一些的 毕竟要区分是左是右 是否为根
{
T = z;
}
else if(z->key < y->key)
{
y->left = z;
}
else
{
y->right = z;
} //对新插入的点处理, 染成红色
z->left = nil;
z->right = nil;
z->color = 'r'; //调整红黑树
rb_insert_fixup(T, z); } RBNode * rb_findmax(RBNode * z) //找到以z为树根的树的最大结点
{
while(z->right != nil)
{
z = z->right;
}
return z;
} RBNode * rb_findmin(RBNode * z) //找到以z为树根的树的最小结点
{
while(z->left != nil)
{
z = z->left;
}
return z;
} RBNode * rb_successor(RBNode * z) //找z的后继
{
if(z->right != nil)
{
return rb_findmin(z->right); //如果z的right不为空 后继就是z的右子树中最小的点
}
else
{
RBNode * y = z->parent;
while(y != nil && z == y->right)
{
z = y;
y = y->parent;
}
return y;
}
} void rb_delete_fixup(RBNode * &T, RBNode * x)
{
RBNode* w;
while(x != T && x->color == 'b')
{
if(x == x->parent->left)
{
w = x->parent->right;
if(w->color == 'r')
{
w->color = 'b';
x->parent->color = 'r';
left_rotate(T, x->parent); w = x->parent->right;
}
if(w->left->color == 'b' && w->right->color == 'b')
{
w->color = 'r';
x = x->parent;
}
else
{
if(w->right->color == 'b')
{
w->left->color = 'b';
w->color = 'r';
right_rotate(T, w);
w = x->parent->right;
} w->color = x->parent->color;
x->parent->color = 'b';
w->right->color = 'b';
left_rotate(T, x->parent);
x = T;
}
}
else
{
w = x->parent->left;
if(w->color == 'r')
{
w->color = 'b';
x->parent->color = 'r';
right_rotate(T, x->parent); w = x->parent->left;
}
if(w->left->color == 'b' && w->right->color == 'b')
{
w->color = 'r';
x = x->parent;
}
else if(w->left->color == 'b')
{
if(w->left->color == 'b')
{
w->right->color = 'b';
w->color = 'r';
left_rotate(T, w);
w = x->parent->left;
} w->color = x->parent->color;
x->parent->color = 'b';
w->left->color = 'b';
right_rotate(T, x->parent);
x = T;
}
}
}
x->color = 'b';
} RBNode * rb_delete(RBNode * &T, RBNode * z) //红黑树 删除节点
{
//y 确定删除的结点是z还是z的后继
RBNode * y;
y = (z->left == nil || z->right == nil) ? z : rb_successor(z); //x 是y的非nil子女 或是 nil
RBNode * x;
x = (y->left != nil) ? y->left : y->right; //无条件令x的parent = y的parent
x->parent = y->parent; //删除y 建立x与y的parent之间的联系
if(y->parent == nil)
{
T = x;
}
else if(y == y->parent->left)
{
y->parent->left = x;
}
else
{
y->parent->right = x;
} //如果y!=z 将y的数据拷贝到z
if(y != z)
{
//z的颜色不变
z->parent = y->parent;
z->left = y->left;
z->right = y->right;
z->key = y->key;
} if(y->color == 'b')
{
rb_delete_fixup(T, x);
}
return y;
}
int main()
{
nil->color = 'b'; //叶子结点都是黑的
nil->left = nil;
nil->right = nil;
nil->parent = nil;
RBNode *T;
T = nil;
RBNode data[];
for(int i = ; i < ; i++)
{
data[i].key = i + ;
RBNode * z = &data[i];
rb_insert(T, z);
} RBNode * x = T->left->left;
rb_delete(T, x); return ;
}
【数据结构】红黑树 C语言代码的更多相关文章
- 高级数据结构---红黑树及其插入左旋右旋代码java实现
前面我们说到的二叉查找树,可以看到根结点是初始化之后就是固定了的,后续插入的数如果都比它大,或者都比它小,那么这个时候它就退化成了链表了,查询的时间复杂度就变成了O(n),而不是理想中O(logn), ...
- java数据结构——红黑树(R-B Tree)
红黑树相比平衡二叉树(AVL)是一种弱平衡树,且具有以下特性: 1.每个节点非红即黑; 2.根节点是黑的; 3.每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的; 4.如图所示,如果一个 ...
- 第三十三篇 玩转数据结构——红黑树(Read Black Tree)
1.. 图解2-3树维持绝对平衡的原理: 2.. 红黑树与2-3树是等价的 3.. 红黑树的特点 简要概括如下: 所有节点非黑即红:根节点为黑:NULL节点为黑:红节点孩子为黑:黑平衡 4.. 实现红 ...
- Java数据结构——红黑树
红黑树介绍红黑树(Red-Black Tree),它一种特殊的二叉查找树.执行查找.插入.删除等操作的时间复杂度为O(logn). 红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点 ...
- 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树
某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...
- 算法设计和数据结构学习_5(BST&AVL&红黑树简单介绍)
前言: 节主要是给出BST,AVL和红黑树的C++代码,方便自己以后的查阅,其代码依旧是data structures and algorithm analysis in c++ (second ed ...
- JAVA中的数据结构 - 真正的去理解红黑树
一, 红黑树所处数据结构的位置: 在JDK源码中, 有treeMap和JDK8的HashMap都用到了红黑树去存储 红黑树可以看成B树的一种: 从二叉树看,红黑树是一颗相对平衡的二叉树 二叉树--&g ...
- Java数据结构和算法(八)--红黑树与2-3树
红黑树规则: 1.每个节点要么是红色,要么是黑色 2.根节点都是黑色节点 3.每个叶节点是黑色节点 3.每个红色节点的两个子节点都是黑色节点,反之,不做要求,换句话说就是不能有连续两个红色节点 4.从 ...
- JAVA中的数据结构 - 1,红黑树
背景: 在JDK源码中, 有treeMap和JDK8的HashMap都用到了红黑树去存储 红黑树可以看成B树的一种: 二叉树-->搜索二叉树-->平衡搜索二叉树-->B树--> ...
随机推荐
- 【AngularJS】—— 11 指令的交互
前面基本了解了指令的相关内容: 1 如何自定义指令 2 指令的复用 本篇看一下指令之间如何交互.学习内容来自<慕课网 指令3> 背景介绍 这例子是视频中的例子,有一个动感超人,有三种能力, ...
- URL、Session、Cookies、Server.Transfer、Application和跨页面传送,利弊比较
URL.Session.Cookies.Server.Transfer.Application和跨页面传送.-本题考查面试者对ASP.NET中多页面传值的理解是否全面.因为ASP.NET的页面表单提交 ...
- dede自定义表单增加添加时间怎么弄
我们在用dedecms添加自定义表单时有时想要设置一个用户提交的时间,方便查询,比如我们的客服人员查询昨天晚上下班后有哪些订单是刚生成的,比较好查看,如下图所示.那么,dedecms自定义表单增加添加 ...
- InnoDB为什么要使用auto_Increment
在Mysql表设计中,通常会使用一个与业务无关的自增列做为主键.这是因为Mysql默认使用B-Tree索引,你可以简单理解为"排好序的快速查找结构".如下是一个B-Tree的结构图 ...
- 在Mac mini上编译Android源码
参考文章 1.Android 6.0 源代码编译实践 2.编译Android源码致命错误解决方案 实践过程 1.Mac下安装Ubuntu双系统 (1)Ubuntu版本:Ubuntu 15.10 注:实 ...
- Javascript正则表达式匹配替换
根据正则表达式的匹配结果将匹配项替换为*function regReplace(reg, str){ var result, //最终输出结果 out, //每次运行正则exec返回的匹配结果. in ...
- 用 FragmentManager 替换时使用 GoogleMaps 崩溃 app
我要用下面的代码来加载的片段的项已被选定在 NavigationDrawer,然而 MapFragment 包含它里面的谷歌地图片段和它崩溃后试图打开它第二次. 这里是我使用的代码: @Overrid ...
- nginx命令
window cmd 到nginx的文件夹 start nginx 启动命令 nginx -s reload 重新启动 nginx -s stop 关闭 linux 到 sbin ...
- HNU 12888 Encryption(map容器)
题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=12890&courseid=274 解题报告:输入一个有 ...
- BZOJ1588——[HNOI2002]营业额统计
1.题目大意:一个简单的treap模板题(我才不告诉你题目少一句话呢,看discuss去 2.分析:treap模板题 #include <cstdio> #include <cstd ...