红黑树 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 红黑树的更多相关文章

  1. Java集合详解6:这次,从头到尾带你解读Java中的红黑树

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  2. 数据结构Java版之红黑树(八)

    红黑树是一种自动平衡的二叉查找树,因为存在红黑规则,所以有效的防止了二叉树退化成了链表,且查找和删除的速度都很快,时间复杂度为log(n). 什么是红黑规则? 1.根节点必须是黑色的. 2.节点颜色要 ...

  3. JAVA数据结构之红-黑树

    本篇博客我会重点介绍对红-黑树的理解,重点介绍红-黑树的查找,这里我们将要讨论的算法称为自顶向下插入,也就是把沿着树向下查找插入点 Ⅰ.平衡树和非平衡树 平衡树和非平衡树:当插入一组数据关键字是按照升 ...

  4. 红黑树(五)之 Java的实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

  5. java中treemap和treeset实现(红黑树)

    java中treemap和treeset实现(红黑树)   TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...

  6. Java 7之集合类型 - 二叉排序树、平衡树、红黑树---转

    http://blog.csdn.net/mazhimazh/article/details/19961017 为了理解 TreeMap 的底层实现,必须先介绍排序二叉树和平衡二叉树,然后继续介绍红黑 ...

  7. 红黑树 Java实现

    概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

  8. Java实现红黑树

    转自:http://www.cnblogs.com/skywang12345/p/3624343.html 红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉 ...

  9. 红黑树java代码实现

    红黑树 思想源于:https://www.cnblogs.com/nananana/p/10434549.html有解释有图,很清晰(删除时需考虑根节点和兄弟节点的子节点是否存在) package t ...

随机推荐

  1. DOM的方法和属性

    HTML DOM 方法是我们可以在节点(HTML 元素)上执行的动作. HTML DOM 属性是我们可以在节点(HTML 元素)设置和修改的值. 编程接口 可通过 JavaScript (以及其他编程 ...

  2. 【做题笔记】洛谷P1955[NOI2015]程序自动分析

    第一道蓝题祭- 注意到本题中判断的是下标,即,并不是真的判断 \(i\) 是否等于 \(j\) 显然考虑并查集,把所有标记为"相等"的数放在一个集合里,然后最后扫一遍每个数,如果有 ...

  3. Oracle常用函数记录

    Oracle函数 --schema:hcf --不带任何参数 http://www.cnblogs.com/wuyisky/archive/2010/05/11/oracle_function.htm ...

  4. 用Python开发实用程序 – 计算器

    一段时间前,自己制作了一个库 “sui-math”.这其实是math的翻版.做完后,python既然可以轻易的完成任何的数学计算,何不用python开发一个小程序专门用以计算呢? 现在我们越来越依赖于 ...

  5. jmeter的使用---控制器

    1.如果(If)控制器.Switch Controller if控制语句,判断字段是否存在,或者符合,执行不同的逻辑 2.简单控制器 一次进件流程,需要不同模块的数据,例如登陆,提交个人信息,信用认证 ...

  6. C#连接SQL Server数据库(二)

    执行SQL语句:Command对象 1.Command对象概述   Command对象是一个数据命令对象,主要功能是向数据库发送查询.更新.删除.修改操作的SQL语句.Command对象主要有以下几种 ...

  7. supervisor的使用点滴

    supervisor的安装 pip install supervisor 安装成功后步骤 1.创建配置文件 echo_supervisord_conf  > /etc/supervisord.c ...

  8. Java - Test - TestNG: testng.xml 元素 group

    1. 概述 group 相关的元素 groups run 其他相关(不准备提了) package class include exclude 2. 背景 准备 了解了 class 及其子元素 问题 对 ...

  9. Codeforces Round #604 (Div. 2)D(构造)

    构造,枚举起点,如果一个序列成立,那么将它reverse依然成立,所以两个方向(从小到大或从大到小)没有区别,选定一个方向进行探测,直到探测不到以后回头,只要所给数据能成立,那么能探测进去就能探测出来 ...

  10. Web基础了解版07-EL表达式-运算符-11个隐式对象

    EL EL(Expression Language)是JSP内置的表达式语言,用以访问页面的上下文以及不同作用域中的对象 ,取得对象属性的值,或执行简单的运算或判断操作.EL在得到某个数据时,会自动进 ...