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

一、规则

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

二、旋转、变换技巧

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

1.插入root

不会违反规则

2.父黑

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

3.父红

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

4.父红,叔红

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

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

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

5.1父红,叔黑,外侧子孙

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

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

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

总结一下,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只有一个内侧外侧的区别。
内侧子孙比外侧要多做一次旋转。目的是把内侧子孙旋转成外侧子孙来做

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

之后的步骤就是和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/

jdk源码分析红黑树——插入篇的更多相关文章

  1. HashMap1.8源码分析(红黑树)

    转载:https://segmentfault.com/a/1190000012926722?utm_source=tag-newest https://blog.csdn.net/weixin_40 ...

  2. 【JDK】JDK源码分析-TreeMap(2)

    前文「JDK源码分析-TreeMap(1)」分析了 TreeMap 的一些方法,本文分析其中的增删方法.这也是红黑树插入和删除节点的操作,由于相对复杂,因此单独进行分析. 插入操作 该操作其实就是红黑 ...

  3. 【JDK】JDK源码分析-LinkedHashMap

    概述 前文「JDK源码分析-HashMap(1)」分析了 HashMap 主要方法的实现原理(其他问题以后分析),本文分析下 LinkedHashMap. 先看一下 LinkedHashMap 的类继 ...

  4. 【JDK】JDK源码分析-HashMap(1)

    概述 HashMap 是 Java 开发中最常用的容器类之一,也是面试的常客.它其实就是前文「数据结构与算法笔记(二)」中「散列表」的实现,处理散列冲突用的是“链表法”,并且在 JDK 1.8 做了优 ...

  5. 【JDK】JDK源码分析-HashMap(2)

    前文「JDK源码分析-HashMap(1)」分析了 HashMap 的内部结构和主要方法的实现原理.但是,面试中通常还会问到很多其他的问题,本文简要分析下常见的一些问题. 这里再贴一下 HashMap ...

  6. JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue

    JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...

  7. JDK 源码分析(4)—— HashMap/LinkedHashMap/Hashtable

    JDK 源码分析(4)-- HashMap/LinkedHashMap/Hashtable HashMap HashMap采用的是哈希算法+链表冲突解决,table的大小永远为2次幂,因为在初始化的时 ...

  8. 【JDK】JDK源码分析-List, Iterator, ListIterator

    List 是最常用的容器之一.之前提到过,分析源码时,优先分析接口的源码,因此这里先从 List 接口分析.List 方法列表如下: 由于上文「JDK源码分析-Collection」已对 Collec ...

  9. 【JDK】JDK源码分析-AbstractQueuedSynchronizer(1)

    概述 前文「JDK源码分析-Lock&Condition」简要分析了 Lock 接口,它在 JDK 中的实现类主要是 ReentrantLock (可译为“重入锁”).ReentrantLoc ...

随机推荐

  1. Dancing Links and Exact Cover

    1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...

  2. UGUI Text(Label)

    环境 Unity 5.3.6f1 关于Best Fit 如果勾选了 Best Fit ,当有大量的文本填充在Text上时,那么文字是不会自动换行的. 打字机效果 在github上已有现成的:https ...

  3. Maven实战:pom.xml与settings.xml

    pom.xml与settings.xml pom.xml与setting.xml,可以说是Maven中最重要的两个配置文件,决定了Maven的核心功能,虽然之前的文章零零碎碎有提到过pom.xml和s ...

  4. iOS开发入门知识归纳

    一.iOS-C基础 二.iOS-Objective-C基础 三.iOS-Swift编程 三.iOS开发简单介绍 四.iOS-UI基础 1.UI控件介绍 2.UI布局-屏幕适配 五.iOS-多线程基础 ...

  5. iOS 多个播放器同时播放,双击全屏,单击退出全屏

    前言:公司需求如下:点击一个按钮播放一个视频,最多同时播放4个:双击某视频让其全屏,单击再恢复原来的样子.IOS的播放器有两种,MPMoviePlayerController,AVAudioPlaye ...

  6. WPF自定义RoutedEvent事件代码段

    今天在写东西的时候,发现常用的代码段里没有RoutedEvent的,因此,写了一个代码段,方便以后使用,顺便记录一下,如何做代码段. 1.在项目中新建一个XML文件,将扩展名修改为snippet. 2 ...

  7. ElasticSearch 5学习(5)——第一个例子(很实用)

    想要知道ElasticSearch是如何使用的,最快的方式就是通过一个简单的例子,第一个例子将会包括基本概念如索引.搜索.和聚合等,需求是关于公司管理员工的一些业务. 员工文档索引 业务首先需要存储员 ...

  8. .Net MVC 网站中配置文件的读写

    网站中有很多需要设置的内容,像网站信息,注册设置,上传设置等.如果保存在数据库中需要单独建张表,表中只有一条记录,这样会让数据库很臃肿,而且频繁存取数据库的效率也是个问题.而保存在config文件里是 ...

  9. java跳出多重嵌套循环

    public class BreaklFor { public static void main(String args[]){ OK: //设置一个标记 使用带此标记的break语句跳出多重循环体 ...

  10. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(25)-权限管理系统-系统管理员(附生成器)

    系列目录 这一节我们要着手建立系统管理员表,但发布之前,我先发布一个代码生成器给大家先用着. 这个生成器是为这个项目而生的,理论不能用于其他项目,而且写得比较潦草,但能用 下载地址 有兴趣要生成器源码 ...