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 ...
随机推荐
- 【资源分享】Gmod动态方框透视脚本
*----------------------------------------------[下载区]----------------------------------------------* ...
- WOW Factor
Recall that string aa is a subsequence of a string bb if aa can be obtained from bb by deletion of s ...
- 结合sqlmap进行sql注入过程
结合sqlmap进行sql注入:(-r后面是通过burp suite抓出来的请求包:-p后面是注入点,即该请求里携带的某个参数) Get请求的注入: ./sqlmap.py -r rss_test.t ...
- office2013激活工具,可以激活新版本office 2013
耽误一上午没激活成功,最后还是找到了激活文件KMSpico v9.0.6.zip 链接:https://pan.baidu.com/s/1WEyJm8kVnqDONRJRHTRQiQ 提取码:4h45 ...
- kill pkill
首先说一下kill命令,它是通过pid(进程ID)来杀死进程,要得到某个进程的pid,我们可以使用ps(process status)命令,默认情况下,kill命令发送给进程的终止信号是15,但是有些 ...
- 【游戏体验】Infiltraing the Airship(火柴人潜入飞船)
这款作品的游戏性非常高 而且很多地方都是玩梗 不乏趣味和幽默 推荐试玩 个人测评 游戏性 10/10 音乐 9/10 剧情 8/10 总评 27/30
- Codeforces Round #618 (Div. 1)C(贪心)
把所有数看作N块,后面的块比前面的块小的话就合并,这个过程可能会有很多次,因为后面合并后会把前面的块均摊地更小,可能会影响更前面地块,像是多米诺骨牌效应,从后向前推 #define HAVE_STRU ...
- 【做题笔记】P6014 [CSGRound3]斗牛
仔细读题:另外两张牌和的个位数即为你所获得的点数.对于Subtask 1,枚举即可.50 分. 考虑:取 \(n-2\) 张牌和取答案的 \(2\) 张牌本质是一样的.因为若取符合条件的 \(n-2\ ...
- c# 泛型demo
private void Fn_Post<T>(T dto, string api) { HttpClient client = new HttpClient(); client.Base ...
- webRTC中回声消除(AEC)模块编译时aec_rdft.c文件报错:
webRTC中回声消除(AEC)模块编译时aec_rdft.c文件报错. 原因是: 局部变量ip跟全局变量冲突的问题,可以将局部变量重新命名一下,就可以通过编译了. aec_rdft.c修改以后文件代 ...