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 ...
随机推荐
- ffmpeg 音频常用命令
ffmpeg的使用方式: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... Stream ...
- HTML学习(13)区块元素和内联元素
HTML 区块元素 大多数 HTML 元素被定义为块级元素或内联元素. 块级元素在浏览器显示时,通常会以新行来开始(和结束). 实例: <h1>, <p>, <ul> ...
- 在同一个tomcat下部署多个springboot项目时,springboot项目无法正常启动的问题
这个问题是基于,不使用springboot内置的tomcat会产生(即使用自己的tomcat时). 今天在部署springboot项目的时候遇到了一个问题,怎么部署都访问不了,在网上查了很多原因,什么 ...
- c#显示行号设置方法
工具→选项→文本编辑器→c#→常规→显示→勾选行号 反之取消即可.
- drf三大组件之认证组件与权限组件
复习 """ 视图家族 1.视图类:APIView.GenericAPIView APIView:作为drf的基础view:as_view()禁用csrf:dispatc ...
- 查询数据操作:distinct
1.作用:distinct 去除重复记录.重复记录,指的是字段值,都相同的记录,而不是部分字段值相同的记录 与之相对的是all,表示所有.在MySQL中默认就是all. 2.例子: select ch ...
- CSS学习(3)样式表
如何插入样式表 插入样式表的方法有三种: 外部样式表(External style sheet) 内部样式表(Internal style sheet) 内联样式(Inline style) 外部样式 ...
- 手写webpack配置文件
webpack是一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX).coffee.样式(含less/sass).图片等都作为模块来使用和处理,它能有Grunt或Gulp所有基本功能. We ...
- 理解ASP.NET Core验证模型 Claim, ClaimsIdentity, ClaimsPrincipal
Claim, ClaimsIdentity, ClaimsPrincipal: Claim:姓名:xxx,领证日期:xxx ClaimsIdentity:身份证/驾照 ClaimsPrincipal: ...
- 连接mongodb服务
语法:mongo.exe ip地址:端口号/数据库名(默认连接test) mongodb的默认端口号:27017 MongoDB内部结构 MongoDB MySQL 文档(Document) 记录 ...