Java 1.8 红黑树
红黑树 R-B Tree
R-B Tree,全称 Red-Black Tree 又称为 红黑树,它是一种特殊的二叉查找树,红黑树的每个节点都有存储位表示节点的颜色,可以是红Red 或者 黑Black
红黑树是相对平衡的二叉树
特性
1.每个节点或者是黑色或者是红色
2.根节点是黑色
3.每个叶子节点(NIL)是黑色,这里叶子节点是为空 NIL 或者 NULL 的叶子节点
4.如果一个节点是红色的,则它的子节点必须是黑色的
5.从一个节点到该节点的子孙节点的所有路径上包含相同数据的黑节点
应用
红黑树的应用比较广泛,主要是用它来存储有序的数据。它的时间复杂度是 O(logn),效率非常高
例如:Java 集合中 TreeSet 和 TreeMap ,C++ STL 中的set、map以及 Linux 虚拟内存管理都是通过红黑树实现的
基本操作 左旋 右旋
红黑树的基本操作是添加、删除。在对红黑树进行添加或者删除后,都会用到旋转方法,为什么呢?因为添加或者删除红黑树中的节点后,红黑树就发生了变化,可能不满足红黑树的 5条性值,也就不再是以可红黑树
而是以可普通的树。通过旋转,可以使得这颗树重新成为红黑树。旋转的目的是让树保持红黑树的特性
1.左旋
对x进行左旋,意味着"将x变成一个左节点",理解左旋之后,看看下面一个更鲜明的例子。你可以先不看右边的结果,自己尝试一下。
2.右旋
总结:
01.左旋 和右旋是相对的两个概念,原理类似
02.发现左旋与右旋是对称的,无论左旋还是右旋,被旋转的树,在旋转前是二叉查找树,在旋转后还是二叉查找树
左旋:x左旋,意味着将 x的右节点设为x的父节点,x将变为 左节点
z
x /
/ \ --(左旋)--> x
y z /
y
右旋:对x 右旋,意味着 将 x 的左节点设为父节点,x 将变为一个右节点
y
x \
/ \ --(右旋)--> x
y z \
z
C 代码
#include<stdio.h>
#include<stdlib.h> #define RED 0
#define BLACK 1 //定义红黑树结点
typedef struct RBTreeNode
{
char color;//颜色
int key;//值
struct RBTreeNode *lchild;//左孩子
struct RBTreeNode *rchild;//右孩子
struct RBTreeNode *parent;//父结点
}Node,*RBTree; //定义红黑树根结点
typedef struct rb_root
{
Node *node;
} RBRoot; //创建红黑树,返回红黑树的根
RBRoot* creat_rbtree()
{
RBRoot *root=(RBRoot*)malloc(sizeof(RBRoot));//定义根结点,并分配空间
root->node=NULL;//初始化
return root;
} //新建一个结点
Node* creat_rbtree_node(int key,Node *parent,Node *lchild,Node *rchild)
{
Node* p;
p=(Node*)malloc(sizeof(Node));
p->key=key;
p->lchild=lchild;
p->rchild=rchild;
p->color=BLACK; return p;
} //左旋
void rbtree_left_rotate(RBRoot *root,Node *x)
{
Node *y=x->rchild;//设置x的右结点等于y
//首先,先找到y的左孩子,它最终被x收养为右孩子
x->rchild=y->lchild;
if (y->lchild!= NULL)
y->lchild->parent = x; y->parent=x->parent;
//x->rchild=y->lchild;
//y->lchild->parent=x; //y缺了左孩子,x成为y的左孩子
if(x->parent==NULL)//当x为根结点的时候
{
root->node=y;//将y设为根结点
}
else//当x不是根节点的时候
{
//y->parent=x->parent;//y接替x做别人的儿子
if(x->parent->lchild==x) //要确定y是做的左孩子还是右孩子
{
x->parent->lchild=y;
}
else
{
x->parent->rchild=y;
}
}
y->lchild=x;//x就位
x->parent=y;
//printf("(对关键字%d进行左旋)",x->key);
} //右旋
void rbtree_right_rotate(RBRoot *root,Node *y)
{
Node *x=y->lchild; y->lchild=x->rchild;
//找到x的右孩子,它最终被y收养为左孩子
if(x->rchild!=NULL)
{
x->rchild->parent=y;
}
x->parent=y->parent;
//此时x的右孩子是空的,y来当x的右孩子
if(y->parent==NULL)//如果y为根结点
{
root->node=x;//将x设为根节点
}
else//当y不是根节点的时候
{
//y->parent=x->parent;//x接替y做别人的儿子
if(y->parent->rchild==y) //要确定x是做的左孩子还是右孩子
{
y->parent->rchild=x;
}
else
{
y->parent->lchild=x;
}
}
x->rchild=y;//y就位
y->parent=x;
//printf("(对关键字%d进行右旋)",y->key);
} //插入修正
void rbtree_insert_fixup(RBRoot *root, Node *node)
{
Node *parent, *gparent;
// 若父节点存在,并且父节点的颜色是红色
while ((parent = node->parent) && (parent->color==RED))
{
gparent = parent->parent; //若“父节点”是“祖父节点的左孩子”
if (parent == gparent->lchild)
{
// Case 1条件:叔叔节点是红色
{
Node *uncle = gparent->rchild;
if (uncle && uncle->color==RED)
{//父、叔变黑,爷变红,对爷进行判断
uncle->color=BLACK;
parent->color=BLACK;
gparent->color=RED;
node = gparent;
continue;
}
} // Case 2条件:叔叔是黑色,且当前节点是右孩子
if (parent->rchild == node)
{
Node *tmp;
rbtree_left_rotate(root, parent);//父左旋
tmp = parent;
parent = node;
node = tmp;
} // Case 3条件:叔叔是黑色,且当前节点是左孩子。
parent->color=BLACK;
gparent->color=RED;
rbtree_right_rotate(root, gparent);
}
else//若“z的父节点”是“z的祖父节点的右孩子”
{
// Case 1条件:叔叔节点是红色
{
Node *uncle = gparent->lchild;
if (uncle && (uncle->color==RED))
{
uncle->color=BLACK;
parent->color=BLACK;
gparent->color=RED;
node = gparent;
continue;
}
} // Case 2条件:叔叔是黑色,且当前节点是左孩子
if (parent->lchild == node)
{
Node *tmp;
rbtree_right_rotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
} // Case 3条件:叔叔是黑色,且当前节点是右孩子。
parent->color=BLACK;
gparent->color=RED;
rbtree_left_rotate(root, gparent);
}
} // 将根节点设为黑色
root->node->color=BLACK;
//printf("对关键字%d进行插入修正",node->key);
} //插入
void rbtree_insert(RBRoot *root,Node *node)
{
Node *y=NULL;
Node *x=root->node; while(x!=NULL)//x为叶子结点跳出循环
{
y=x;
if(x->key>node->key)
{
x=x->lchild;
}
else
{
x=x->rchild;
}
}
node->parent=y; if(y!=NULL)
{
if(node->key<y->key)
{
y->lchild=node;
}
else
{
y->rchild=node;
}
}
else
{
root->node=node;//若y为NULL,说明树为空,则将node设为根节点
} node->color=RED;//将颜色设为红色 //插入修正
rbtree_insert_fixup(root, node);
} int insert_rbtree(RBRoot *root,int key)
{
Node *node;//新建一个结点
node=creat_rbtree_node(key,NULL,NULL,NULL);
if(node==NULL) return -;
else rbtree_insert(root,node);
return ;
} /*
* 中序遍历"红黑树"
*/
void inorder(RBTree tree)
{
if(tree != NULL)
{
inorder(tree->lchild);
printf("%d", tree->key);
if(tree->color==)
{
printf("(RED) ");
}
else
{
printf("(BLACK) ");
}
inorder(tree->rchild);
}
} void inorder_rbtree(RBRoot *root)
{
if (root)
inorder(root->node);
} int main()
{
int a[]={,,,,,,,,,};
int i;//计数器
int key;
int n=sizeof(a)/sizeof(int);
printf("**********原始数据**********\n");
for(i=;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n"); //下面开始创建红黑树
RBRoot *root=NULL;//首先创建红黑树的根
root=creat_rbtree(); for(i=;i<n;i++)
{
printf("== 添加节点: %d\n", a[i]);
insert_rbtree(root,a[i]);
printf("== 中序遍历: ");
inorder_rbtree(root);
printf("\n");
} printf("==向红黑树中插入一个值: ");
scanf("%d",&key);
insert_rbtree(root,key);
printf("\n== 成功插入后的中序遍历: ");
inorder_rbtree(root);
printf("\n");
return ;
}
参考:https://www.cnblogs.com/skywang12345/p/3245399.html
参考:https://blog.csdn.net/weixin_42887391/article/details/82631642
Java 1.8 红黑树的更多相关文章
- Java集合详解6:这次,从头到尾带你解读Java中的红黑树
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
- 数据结构Java版之红黑树(八)
红黑树是一种自动平衡的二叉查找树,因为存在红黑规则,所以有效的防止了二叉树退化成了链表,且查找和删除的速度都很快,时间复杂度为log(n). 什么是红黑规则? 1.根节点必须是黑色的. 2.节点颜色要 ...
- JAVA数据结构之红-黑树
本篇博客我会重点介绍对红-黑树的理解,重点介绍红-黑树的查找,这里我们将要讨论的算法称为自顶向下插入,也就是把沿着树向下查找插入点 Ⅰ.平衡树和非平衡树 平衡树和非平衡树:当插入一组数据关键字是按照升 ...
- 红黑树(五)之 Java的实现
概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...
- java中treemap和treeset实现(红黑树)
java中treemap和treeset实现(红黑树) TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...
- Java 7之集合类型 - 二叉排序树、平衡树、红黑树---转
http://blog.csdn.net/mazhimazh/article/details/19961017 为了理解 TreeMap 的底层实现,必须先介绍排序二叉树和平衡二叉树,然后继续介绍红黑 ...
- 红黑树 Java实现
概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...
- Java实现红黑树
转自:http://www.cnblogs.com/skywang12345/p/3624343.html 红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉 ...
- 红黑树java代码实现
红黑树 思想源于:https://www.cnblogs.com/nananana/p/10434549.html有解释有图,很清晰(删除时需考虑根节点和兄弟节点的子节点是否存在) package t ...
随机推荐
- Matlab filter常用函数
Filtering and Analysis Functions Filtering Function Description fftfilt Filters a signal with a digi ...
- monkey工具使用(未完待续)
monkey命令详解: 转自:http://blog.csdn.net/jlminghui/article/details/38238443 http://www.cnblogs.com/wfh198 ...
- 编程道拓扑bcd.top 0x01/ 开局第一篇: 随便聊聊/ 随笔
0x01 开局 编程道拓扑(bcd.top)是一个前端从业者的思考和总结, 如果你喜欢, 欢迎关注! 作者是一个前端从业者, 本系列会总结作者在工作和学习中的一些思考, 会有具体的技术点, 也会有关于 ...
- 6_13古代象形符号(UVa1103)<图的连通块的应用>
给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 输出说明:For each test case, display its ...
- JetBrains PyCharm 2018.2.1 x64永久激活码
812LFWMRSH-eyJsaWNlbnNlSWQiOiI4MTJMRldNUlNIIiwibGljZW5zZWVOYW1lIjoi5q2j54mIIOaOiOadgyIsImFzc2lnbmVlT ...
- Django视图层、模板层
过滤器方法 upper 大写方式输出 add 给value加上一个数值 capfirst 第一个字母大写 center 输出指定长度的字符串,把变量居中 cut 删除指定字符串 date 格式化日期 ...
- Panda的学习之路(3)——pandas 设置特定的值&处理没有数据的部分
先设定好我们的dataframe: # pandas 设置特定的值 dates=pd.date_range(',periods=6) # print(dates) df=pd.DataFrame(np ...
- 046_使用Scanner获得键盘输入 047_控制语句介绍 048_控制语句_if单选择结构 049_ifelse双选择结构 050_ifelseifelse多选择结构
046_使用Scanner获得键盘输入 package test_package;import java.util.Scanner;/** * 测试获得键盘输入 * @author * */publi ...
- Atcoder Beginner Contest 147D(按位处理)
把每个数字每一位上二进制数字取出,求答案时直接用N个数里这一位是0的个数乘上这一位是1的个数然后乘上二的这一位次方,注意所有可能溢出的地方都要对mod取模. #define HAVE_STRUCT_T ...
- 2017年陕西省网络空间安全技术大赛——一维码——Writeup
<!doctype html> 2017年陕西省网络空间安全技术大赛——一维码——Writeup 先判断下载的文件flag.png确实是png格式的图片后(binwalk, file命令均 ...