【数据结构】红黑树 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树--> ...
随机推荐
- 关于hibernate链接数据源的配置参数详细解释(转)
具体使用方法还可以参考以下地址: http://blog.csdn.net/xb12369/article/details/41517409 以下信息转自: http://baike.baidu.co ...
- 第2月第1天 命令(Command)模式
http://www.tracefact.net/Design-Pattern/Command.aspx 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请 ...
- git之remote branch controller(远程分支控制)
1.创建本地分支 git branch //查看远程分支 git checkout -b branch_name //创建远程分支 在查看分支git branch 2.将分支提交到远程仓库 此时远程 ...
- 01什么是ExtJs?
前言: 我之前是搞EasyUI+KO.js的,由于最近项目需要用到ExtJs.因此.边学边记录我的学习历程,希望能给自己和大家一点帮助. 1.0什么是ExtJs? 首先,什么是ExtJs呢?ExtJs ...
- SNMP进阶
管理信息库:MIB 我们要扩展mib首先必须清楚mib是如何定义的,用的什么语言,有哪些约定,遵循哪些规则等等.这些基本东西掌握过后,我们就可以很轻松的来写自己的mib文件了. 所谓管理信息库,或者M ...
- C++关键字:mutable(转)
参考:http://blog.csdn.net/hxz_qlh/article/details/14475573 修饰成员变量,在const成员函数中可修改它,在C++中还从未用过这个关键字.
- Python自动化装饰器问题解疑
问题一 到底是怎么执行的? import time def timer(timeout=0): def decorator(func): def wrapper(*args, **kwargs): # ...
- 10. JEB1.5 插件编写二
一些实例 1. 遍历当前光标处函数所有的Element Java代码: import java.io.*; import java.util.List; import jeb.api.IScript; ...
- phpcms新闻轮播图实现
首页如果有新闻的轮播图,点击图片可以进入相关的新闻.因为已经使用外部js轮播插件,所以想不修改插件进行轮播 我用的js插件是yx-rotaion插件,配合phpcms的get工具箱对新闻进行读取并抽取 ...
- rpm包制作(待实验)
作者:firefoxbug 时间:July 18, 2014 rpm包命名规范 对于rpm包的命名符合如下规范. %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm N ...