`
noble510520
  • 浏览: 56531 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

jdk源码分析红黑树——插入篇

    博客分类:
  • java
阅读更多
红黑树是自平衡的排序树,自平衡的优点是减少遍历的节点,所以效率会高。如果是非平衡的二叉树,当顺序或逆序插入的时候,查找动作很可能会遍历n个节点
红黑树的规则很容易理解,但是维护这个规则难。

一、规则

1.每个节点要么是红色、要么是黑色
2.根节点一定是黑色
3.红色节点不可以连续出现(父节点、子节点不可同时为红)
4.从任意节点出发,到树底的所有路线,途径的黑节点数量必须相同
在修改红黑树的时候,切记要维护这个规则。一般默认插入红色节点(除非是root节点),插入后再进行旋转和颜色变换

二、旋转、变换技巧

关于旋转和颜色变换有几种情况:

1.插入root

不会违反规则

2.父黑

插入节点的父节点是黑色,不会违反规则

3.父红

插入节点的父节点是红色,一定违反规则(违反规则3)(因为默认插入红色节点),此时就需要修复红黑树了。这种情况下又细分为几种情况

4.父红,叔红

父节点和叔节点均为红色(违反规则3)

1

这种情况下就把父节点和叔节点都改成黑色,然后曾节点改为红色

2

可是此时,如果曾节点是根节点的话,那么必须将曾节点转为黑色。
所以一般在修补红黑树的方法的最后,会强制将根节点转为黑色
这种情况可能又会导致5.1的情况

5.1父红,叔黑,外侧子孙

父节点是红色,叔节点是黑色或者null,且新增节点是曾节点的外侧子孙(违反规则3)
外侧子孙:A点是B点的左-左-....-左或者右-右-..-右,那么A是B的外侧子孙,否则A是B的内侧子孙
符号解释:
N:新插入的节点,P:父节点,G:曾节点,U:叔节点

3

此时就需要将G点旋转,这里是右旋

4

不过此时颜色还有冲突,还要调整一下颜色
将P与G的颜色对调,既P变为黑色,G变为红色

5

总结一下,5.1的步骤:
step1:P->黑
step2:G->红
step3:将G旋转

5.1.1关于旋转的方向

旋转有左旋右旋,具体是看父节点是曾节点的左节点还是右节点
P是G的左节点,那么就将G右旋(因为要把P移动到G的位置)
P....G....右节点.....................G左旋

5.2父红,叔黑,内侧子孙

父节点是红色,叔节点是黑色或者null,且新增节点是曾节点的内侧子孙(违反规则3)
外侧子孙:A点是B点的左-左-....-左或者右-右-..-右,那么A是B的外侧子孙,否则A是B的内侧子孙
5.2跟5.1只有一个内侧外侧的区别。
内侧子孙比外侧要多做一次旋转。目的是把内侧子孙旋转成外侧子孙来做

6

这里的N就是G的内侧子孙,现在要把N变成G的外侧子孙。
将P旋转(这里是左旋),让N旋转到P的位置

7

之后的步骤就是和5.1处理外侧子孙的一样了。

5.2.1内侧转外侧的旋转方向

根据P点和N的相对位置,当N是P的右节点,则将P左旋,否则将P右旋
目的是让N旋转到P的位置
总结情况:
1.插入的是根节点,不违反规则
2.插入点的父节点是黑色,不违反规则
3.插入点的父、叔节点是红色,将父、叔转成黑色,然后将曾节点转成红色
4.插入点的父是红色、叔节点是黑色或者null,通过旋转和转变颜色,注意内侧外侧子孙!

三、分析TreeMap源码

jdk中的红黑树实现是TreeMap。

每次put之后,都会调用这个方法去维护红黑树的规则

    private void fixAfterInsertion(Entry<K,V> x) {
        x.color = RED;
        while (x != null && x != root && x.parent.color == RED) {//父节点是红色
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//父节点是曾节点的左节点
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {//父、叔节点都是红色,情况4
	                //将父节点和叔节点变为黑色,曾节点变为红色
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {//父节点是红色,叔节点是黑色或者null
                    if (x == rightOf(parentOf(x))) {//内侧子孙
                        x = parentOf(x);
                        rotateLeft(x);//旋转成外侧子孙
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));//旋转曾节点
                }
            } else {//父节点是曾节点的右节点
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        root.color = BLACK;//强制将根节点转成黑色
	}



查看原文:http://blog.zswlib.com/2016/11/01/jdk%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%e7%ba%a2%e9%bb%91%e6%a0%91-%e6%8f%92%e5%85%a5%e7%af%87/

0
1
分享到:
评论

相关推荐

    JDK源码剖析之红黑树TreeMap.pptx

    JDK源码剖析之红黑树TreeMap,偶然看见,传上来分享一下

    linux安装jdk(csdn)————程序.pdf

    Linux安装JDK指南 Linux安装JDK是开发者和系统管理员最常见的任务之一。正确安装JDK对于Java应用程序的运行至关重要。本文将指导您如何在Linux系统上安装JDK。 一、解压JDK 安装JDK的第一步是解压缩JDK安装包。...

    Android-jdk源码阅读

    "Android-jdk源码阅读"这个主题聚焦于分析Java标准库中的`TreeMap`类,这是一个基于红黑树数据结构实现的有序映射。在这个主题中,我们将探讨`TreeMap`的内部工作原理,特别是它如何利用红黑树来实现高效的插入、...

    centos配置JDK环境(csdn)————程序.pdf

    在Linux系统中,尤其是对于开发和运维人员来说,配置Java Development Kit (JDK) 的环境变量是必备的操作。本文将详细讲解如何在CentOS操作系统上配置JDK环境,以确保Java程序可以顺利运行。 首先,我们需要理解...

    jdk源码(完整版)

    **Java Development Kit (JDK) 源码详解** JDK,即Java Development Kit,是Java编程语言的核心组件,包含了编译器、运行时环境、工具集和其他必要的资源,用于开发和运行Java应用程序。这里提到的"jdk源码(完整版...

    自己重新编译的jdk源码jar包

    对于想了解JDK源码的朋友来说,通过调试JDK源码来学习是一个常用的方法。但是默认的情况下eclipse是不支持进入jdk源码中进行调试和显示当前变量的。 我们要明白在jdk中,sun对rt.jar中的类编译时,去除了调试信息,这样...

    JDK源码阅读笔记

    JDK源码阅读笔记

    关于jdk动态代理的源码剖析

    ### 关于JDK动态代理的源码剖析 #### 一、引言 在Java开发过程中,动态代理技术是一项非常实用的技术,它可以帮助我们实现在不修改原有代码的基础上为方法增加额外的功能,比如日志记录、权限校验等。本文将深入...

    JDK源码阅读笔记LearningJDK

    JDK源码阅读笔记

    jdk-8u60源码

    最后,`.jcheck`可能是源码静态分析工具的输出或配置,这类工具用于检查源码质量,发现潜在的错误和不符合编码规范的地方。了解这些工具的使用,可以帮助我们在开发过程中保持代码的整洁和一致性。 总的来说,深入...

    良葛格————JavaJDK5.0学习笔记PDF

    良葛格————JavaJDK5.0学良葛格————JavaJDK5.0学习笔记PDF.rar习笔记PDF.rar良葛格良葛格————JavaJDK5.0学习笔记PDF.rar————JavaJDK5.0学习笔记PDF.rar良葛格————JavaJDK5.0学习笔记PDF.rar良...

    jdk1.8 源码中文版,jdk直接显示中文注释

    下载后直接去本机jdk目录里替换jdk中的src.zip 再打开idea就能看到中文版的源码注释 示例 https://blog.csdn.net/a7459/article/details/106495622

    JDK源码选读

    8. **异常处理**:JDK中的`java.lang.Throwable`类是所有异常的基类,源码分析能让我们了解异常的层次结构和捕获、处理机制。 9. **并发工具**:`java.util.concurrent`包提供了高级并发工具,如`ExecutorService`...

    JDK源码,整合所有内容

    通过阅读和分析JDK1.8的源码,开发者不仅可以深入了解Java语言的实现,还能学习到优秀的编程实践和设计模式,为日常开发工作提供强大支持。同时,对于优化代码性能、解决并发问题以及深入理解Java生态系统有着不可...

    jdk6 源码 SRC

    jdk6 源码jdk6 源码jdk6 源码jdk6 源码jdk6 源码jdk6 源码

    深入浅出JDK源码

    10. **性能优化**:书中可能会介绍如何通过分析JDK源码来找出性能瓶颈,并提供优化建议,例如通过JVM调优参数调整内存配置,或者使用并发工具进行性能提升。 以上只是部分可能涵盖的内容,实际书籍可能还涉及更多的...

    java的jdk源码包

    第一步:安装完jdk之后,打开jdk所在目录,里面有个src.zip,这就是此jdk的所有源码 第二步:找到之后我们开始导入,选中项目点击右键,选中Build Path栏中的Configure Build Path,在Libraries中我们打开JRE ...

    jdk源码包jdk-11.0.1

    【描述】"jdk源码包"意味着这个压缩文件包含了Java开发工具集(JDK)的所有源代码。通过分析这些源码,开发者可以学习到Java语言的内部工作原理,包括类库、虚拟机(JVM)以及各种工具的实现细节。 【标签】"jdk"和...

    补充资料(HashMap红黑树).rar

    在JDK1.8及以后的版本中,HashMap在内部使用了红黑树(Red-Black Tree)来优化高负载因子下的性能。红黑树是一种自平衡二叉查找树,它的特性使得插入、删除和查找操作的时间复杂度在平均情况下保持在O(log n)。这里...

    jdk源码阅读.zip

    JDK1.8对集合框架进行了优化,例如`HashMap`引入了红黑树结构,提高了查找、插入和删除操作的性能。此外,`Stream API`的引入为集合操作提供了更简洁、链式编程的风格,如`filter()`、`map()`和`reduce()`等方法,极...

Global site tag (gtag.js) - Google Analytics