红黑树是平衡的二叉树,它不是一个完美的平衡二叉树,但是在动态插入过程中平衡二叉搜索树的代价相对较高,所以红黑树就此出现,下面就让爱站技术频道小编带你一起进入下文了解一下吧!

一、红黑树所处数据结构的位置:

在JDK源码中, 有treeMap和JDK8的HashMap都用到了红黑树去存储

红黑树可以看成B树的一种:

从二叉树看,红黑树是一颗相对平衡的二叉树

二叉树-->搜索二叉树-->平衡搜索二叉树--> 红黑树

从N阶树看,红黑树就是一颗 2-3-4树

N阶树-->B(B-)树

故我提取出了红黑树部分的源码,去说明红黑树的理解

看之前,理解红黑树的几个特性,后面的操作都是为了让树符合红黑树的这几个特性,从而满足对查找效率的O(logn)

二、红黑树特性,以及保持的手段

1.根和叶子节点都是黑色的

2.不能有有连续两个红色的节点

3.从任一节点到它所能到达得叶子节点的所有简单路径都包含相同数目的黑色节点

这几个特效,个人理解就是规定了红黑树是一颗2-3-4的B树了,从而满足了O(logn)查找效率

保持特性的手段,通过下面这些手段,让红黑树满足红黑树的特性,如果要尝试理解,可以从2-3-4树的向上增长,后面有详细介绍

当然,这些改变也都是在O(logn)内完成的,主要改变方式有

1.改变颜色

2.左旋

3.右旋

三、从JDK源码来理解

主要看我的注释,逻辑的理解

先看TreeMap

//对treeMap的红黑树理解注解. 2017.02.16 by 何锦彬 JDK,1.7.51

/** From CLR */

private void fixAfterInsertion(Entryx) {

//新加入红黑树的默认节点就是红色

x.color = RED;

/**

* 1. 如为根节点直接跳出

*/

while (x != null && x != root && x.parent.color == RED) {

if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {

//如果X的父节点(P)是其父节点的父节点(G)的左节点

//即 下面这种情况

/**

* G

* P(RED) U

*/

//获取其叔(U)节点

Entryy = rightOf(parentOf(parentOf(x)));

if (colorOf(y) == RED) {

// 这种情况,对应下面 图:情况一

/**

* G

* P(RED) U(RED)

* X

*/

//如果叔节点是红色的(父节点有判断是红色). 即是双红色,比较好办,通过改变颜色就行. 把P和U都设置成黑色然后,X加到P节点。 G节点当作新加入节点继续迭代

setColor(parentOf(x), BLACK);

setColor(y, BLACK);

setColor(parentOf(parentOf(x)), RED);

x = parentOf(parentOf(x));

} else {

//处理红父,黑叔的情况

if (x == rightOf(parentOf(x))) {

// 这种情况,对应下面 图:情况二

/**

* G

* P(RED) U(BLACK)

* X

*/

//如果X是右边节点

x = parentOf(x);

// 进行左旋

rotateLeft(x);

}

//左旋后,是这种情况了,对应下面 图:情况三

/**

* G

* P(RED) U(BLACK)

* X

*/

// 到这,X只能是左节点了,而且P是红色,U是黑色的情况

//把P改成黑色,G改成红色,以G为节点进行右旋

setColor(parentOf(x), BLACK);

setColor(parentOf(parentOf(x)), RED);

rotateRight(parentOf(parentOf(x)));

}

} else {

//父节点在右边的

/**

* G

* U P(RED)

*/

//获取U

Entryy = leftOf(parentOf(parentOf(x)));

if (colorOf(y) == RED) {

//红父红叔的情况

/**

* G

* U(RED) P(RED)

*/

setColor(parentOf(x), BLACK);

setColor(y, BLACK);

setColor(parentOf(parentOf(x)), RED);

//把G当作新插入的节点继续进行迭代

x = parentOf(parentOf(x));

} else {

//红父黑叔,并且是右父的情况

/**

* G

* U(RED) P(RED)

*/

if (x == leftOf(parentOf(x))) {

//如果插入的X是左节点

/**

* G

* U(BLACK) P(RED)

* X

*/

x = parentOf(x);

//以P为节点进行右旋

rotateRight(x);

}

//右旋后

/**

* G

* U(BLACK) P(RED)

* X

*/

setColor(parentOf(x), BLACK);

setColor(parentOf(parentOf(x)), RED);

//以G为节点进行左旋

rotateLeft(parentOf(parentOf(x)));

}

}

}

//红黑树的根节点始终是黑色

root.color = BLACK;

}

再看看HashMap的实现,在HashMap中,在JDK8后开始用红黑树代替链表,查找由O(n) 变成了 O(Logn)

源码分析如下:

for (int binCount = 0; ; ++binCount) {

if ((e = p.next) == null) {

p.next = newNode(hash, key, value, null);

//JDK8 的hashmap,链表到了8就需要变成颗红黑树了

if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

treeifyBin(tab, hash);

break;

}

红黑树的维护代码部分如下:

//hashmap的红黑树平衡

static TreeNodebalanceInsertion(TreeNoderoot,

TreeNodex) {

x.red = true;

//死循环加变量定义,总感觉JAVA很少这样写代码 哈

for (TreeNodexp, xpp, xppl, xppr;;) {

//xp X父节点, XPP X的祖父节点, XPPL 祖父左节点 XXPR 祖父右节点

if ((xp = x.parent) == null) {

x.red = false;

return x;

}

// 如果父节点是黑色, 或者XP父节点是空,直接返回

else if (!xp.red || (xpp = xp.parent) == null)

return root;

// 下面的代码就和上面的很treeMap像了,

if (xp == (xppl = xpp.left)) {

// 第一种情况, 赋值xppl

//父节点是左节点的情况,下面这种

/**

* G

* P(RED) U

*/

if ((xppr = xpp.right) != null && xppr.red) {

//如果红叔的情况

// 这种情况,对应下面 图:情况一

/**

* G

* P(RED) U(RED)

* X

*/

//改变其颜色,

xppr.red = false;

xp.red = false;

xpp.red = true;

x = xpp;

}

else {

// 黑叔的情况

// 这种情况

/**

* G

* P(RED) U(BLACK)

*/

if (x == xp.right) {

//如果插入节点在右边 这种

// 这种情况,对应下面 图:情况二

/**

* G

* P(RED) U(BLACK)

* X

*/

//需要进行左旋

root = rotateLeft(root, x = xp);

xpp = (xp = x.parent) == null ? null : xp.parent;

}

//左旋后情况都是这种了,对应下面 图:情况三

/**

* G

* P(RED) U(BLACK)

* X

*/

// 到这,X只能是左节点了,而且P是红色,U是黑色的情况

if (xp != null) {

//把P改成黑色,G改成红色, 以G为节点进行右旋

xp.red = false;

if (xpp != null) {

xpp.red = true;

root = rotateRight(root, xpp);

}

}

}

}

else {

//父节点在右边的

/**

* G

* U P(RED)

*/

//获取U

if (xppl != null && xppl.red) {

//红父红叔的情况

/**

* G

* U(RED) P(RED)

*/

xppl.red = false;

xp.red = false;

xpp.red = true;

x = xpp;

}

else {

if (x == xp.left) {

//如果插入的X是右节点

/**

* G

* U(BLACK) P(RED)

* X

*/

root = rotateRight(root, x = xp);

xpp = (xp = x.parent) == null ? null : xp.parent;

}

//右旋后

/**

* G

* U(BLACK) P(RED)

* X

*/

if (xp != null) {

//把P改成黑色,G改成红色,

xp.red = false;

if (xpp != null) {

xpp.red = true;

//以G节点左旋

root = rotateLeft(root, xpp);

}

}

}

}

}

情况图如下

情况1

情况2

情况3

JDK源码处理红黑树的流程图

可见,其实处理逻辑实现都一样的

三、个人对红黑树理解的方法

1. 如何理解红黑树的O(lgN)的特性?

从2-3-4树去理解

红黑树,其实是一颗 2-3-4的B树,B树都是向上增长的,如果不理解向上增长可以先看看2-3树,这样理解就能知道为什么能O(logn)的查找了

2.如何理解红黑树的红黑节点意义?

可以把红色节点看成是连接父节点的组成的一个大节点(2个或3个或4个节点组成的一个key),如下:

(此图转自网上)

红色的就是和父节点组成了大节点,

比如

节点7和6,6是红色节点组成,故和它父节点7组成了一个大节点,即 2-3-4树的 6, 7节点

又如

节点 9和10和11,9和10为红色节点,故和10组成了一个2-3-4的3阶节点, 9,10,11(注意顺序有的关性)

3.B树是如何保持O(lgn)的复杂度的呢?

B+树都是从底布开始往上生长,自动平衡,如 2-3-4树,当节点达到了3个时晋升到上个节点,所以不会产生单独生长一边的情况,形成平衡。

留个问题

4.数据库里的索引为什么不用红黑树而是用B+树(Mysql)呢?

后续解答

爱站技术频道小编今天就为大家带来了带你真正理解Java数据结构中的红黑树,大家了解的怎样了呢?相信我们的介绍能为你带来一定的帮助。

红黑树在java中的作用_带你真正理解Java数据结构中的红黑树相关推荐

  1. java中的多态性_[转载] c++多态与java多态性_Java中的多态性

    参考链接: Java中的加法和串联 c++多态与java多态性 Polymorphism is one of the core concepts of OOPS paradigm. The meani ...

  2. java中 jacob作用_【JAVA】JACOB使用简介

    它允许在java中调用com接口自动组件,它使用JNI(本地调用程序)来进行本地调用COM库.它可运行在x86和支持32位和64位Java虚拟机 X64的环境. 测试源码包: 密码: ej9u JAC ...

  3. java中过滤流_第十四讲 Java中的字节流和过滤流

    第十四讲Java中的字节流和过滤流 主要内容 InputStream和FileInputStream OutputStream和FileOutputStream 文件字节IO流应用举例 过滤流类和常用 ...

  4. java中接口文件创建_功能接口简介–在Java 8中重新创建的概念

    java中接口文件创建 世界各地的所有Java开发人员都将至少使用以下接口之一:java.lang.Runnable,java.awt.event.ActionListener,java.util.C ...

  5. java中person作用_以下Java程序中Person(){};是什么意思,有什么作用?

    匿名用户 1级 2013-08-20 回答 Person()方法是用来创建实例的构造方法,例如你要创建一个Person类的实例就需要new Person(),这里的Person()就是Person类的 ...

  6. java中settimeout作用_关于setTimeout的妙用

    定义 在指定的延迟时间之后调用一个函数或执行一个代码片段 这个是setTimeout最主要的功能,但也是很坑的地方,首先javascript其实是运行在单线程的环境下,意味者定时器会在未来的某个时间支 ...

  7. java弱引用怎么手动释放,十分钟理解Java中的弱引用,十分钟java引用

    十分钟理解Java中的弱引用,十分钟java引用 本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,帮助大家理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限 ...

  8. java底层原理书籍_阿里面试题:Java中this和super关键字的底层实现原理

    知道的越多,不知道的就越多,业余的像一棵小草! 编辑:业余草 来源:https://www.xttblog.com/?p=5028 B 站:业余草 最近一个粉丝加我说,接到了阿里的面试,问问我阿里会面 ...

  9. 浅谈计算机教学论文,浅谈计算机在教学中的作用_优秀论文

    <浅谈计算机在教学中的作用_优秀论文>由会员分享,可在线阅读,更多相关<浅谈计算机在教学中的作用_优秀论文(5页珍藏版)>请在人人文库网上搜索. 1.浅谈计算机在教学中的作用论 ...

最新文章

  1. Tian Ji -- The Horse Racing
  2. 一个 Cobol 程序员的告白
  3. 计算机有残留office,电脑中无法安装Office2013删除残留文件的方法
  4. 拉格朗日插值的优缺点_拉格朗日与牛顿插值法的比较
  5. 作为函数的mixin
  6. python线性回归可视化_【Python可视化5】Seaborn之线性回归
  7. 基于 Linux 的文件操作 网络编程的最后一环
  8. ViewPager里面ImageView图片切换出现bug
  9. 项目中坑记录:mongo 插入失败无提示
  10. EXCEL-VBA函数:公历转农历,返回格式YYYY-MM-DD
  11. 谷歌浏览器访问网站无法加载验证码图片问题
  12. Eclipse使用教程(图文详解)+ 2020版eclipse配置tomcat + 配置JDK
  13. 仿真软件Multisim 10下载地址与破解补丁
  14. python攻击校园网_python爬虫 模拟登陆校园网-初级
  15. 盛唐领土争夺战读后感
  16. 笔记本辐射与日常电器辐射对比
  17. Java Files.walk示例
  18. Arduino基础入门篇(认识开发板和面包板)
  19. 基于Springboot + Vue2.0开发的 IM 在线聊天
  20. 20V,30V,40V输入的LDO稳压芯片

热门文章

  1. 直播丨国产数据库的机遇与挑战
  2. OpenHarmony移植案例:如何适配服务启动引导部件bootstrap_lite
  3. 华为中国生态大会2021举行在即,GaussDB将重磅发布5大解决方案
  4. 谁说Python的shutil不支持7z解压缩,我来教你扩展它的功能!
  5. 【华为云技术分享】为什么说物联网平台是城市数字化的必备底座
  6. 【华为云技术分享】DAS文件上传组件的进化
  7. 【华为云技术分享】《跟唐老师学习云网络》—router路咋走啊
  8. 补习系列(13)-springboot redis 与发布订阅
  9. 红橙Darren视频笔记 圆点loadingView 动画ANR
  10. 4由通道检测_博唐平四通道糖化血红蛋白检测仪通过上海临检中心性能验证(二)...