jdk1.8TreeMap的红黑树实现原理

1.8的TreeMap是通过红黑树实现的,下面看看是怎么实现的。

TreeMap初始化的时候会初始化下列参数,第一个Comparator是可以自己定义实现的一个比较的实现,默认为Null,那么默认的比较方式就是compare方法。root默认为Null。其中Entry内部维护了left,right,parent,color  其中color默认是black。

默认构造函数
默认属性

下面我们来看看依次添加会发生哪些变化?

例子1:依次添加1、2、3,从下面的代码可以看到,如果跟节点为空,则直接把第一个对象包装为Entry对象,然后设置为根root,返回null。现在存放第二个对象,此事后显然跟节点不为Null了

设置根节点

添加1完成后的情况如下:


添加节点1并设置为根

跟节点不为null情况下然后我们判断比较对象为不为null,如果不为null,则走下面的方法,如果为null,则走最先的else。默认情况下我们一般都不会去设置设个对象。所以这里不看了。其实流程和默认的是一样的,唯一不同是比较方式不同。

根据自定义的比较方式设置

下面是默认的比较,其实很简单,key不能为null,然后把我们的key强制转换为比Comparable对象,然后先用parent保存t(当前是根节点),对新加入的节点和t的key比较,这里的t其实是始终指向寻位路径的节点,如果比较结果<0则表示比当前节点的key小,然后寻位到左节点,如果>0则寻位到右节点,然后判断是不是Null,如果是null,说明已经找到了该对象应该存放的位置。如果不为Null,然后继续先把该节点保存为parent,然后在比较新加对象和当前节点的大小,然后决定是走左边还是走右边,然后追踪到下一个节点循环追踪,直到该位置为Null为止。

追踪路径过程

找到该位置后,先把传进来的对象包装为entry对象,然后传入父节点(在上一步中始终保存着追踪节点),然后通过父节点来执行该位置。完成后进入了fixAfterInsertion方法中。这个方法完成了红黑树的自调整。也就是红黑树的核心。

保存节点并设置节点引用关系过程

在fixAfterInsertion方法中,进来后首先把新加入的对象的color设置为红色。由此可见,红黑树的核心是每加入一个新节点首先设置为红色,然后再进行调整。然后再进行判断,节点不为null且节点不是root,且父节点的颜色为红色才进入调整,如果条件不满足直接跳过这个while循环,直接设置根节点为黑色,就完成了添加操作。

判断是否需要调整
始终保持根节点为黑色。

添加了2后的情况如下:

2添加完成

下面看继续添加3:

前序不表,直接看添加后的结果,此时,while里面的判断显然满足了判断条件,父节点为red,进入到循环里面。

添加后未调整前

首先来看进入后的第一个判断,parentOf方法就是返回当前传入对象的父节点,然后leftOf就是返回传入对象的左子节点。此时我们的对象x是新加入的3,从表达式可以看出是在判断x节点的父节点是祖父节点的左子节点还是右子节点,如果是左子节点则进入里面,我们先看看这时候做了些什么。


(如上图)如果判断x节点的父节点是祖父节点的左子节点,则先把右子节点拿到,然后判断右子节点的color是不是红色,如果是,则先把上图中的  左  设置为黑色,然后把  右   设置为黑色,祖父节点设置为红色,然后把当前节点替换为祖父节点。然后while条件判断。

如果是左路径调整方式

如果不是红色,则判断当前节点是不是父节点的右节点,如果是,则把当前节点(指向新加入节点的对象x)指向父节点,然后进入rotateLeft方法进行左旋转,然后在在这个基础上进行颜色改变。这里先不看怎么旋转的。

如果当前节点是父节点的左子节点,则把父节点设置为黑色,祖父节点的右子节点设置为红色,把当前节点(指向新加入节点的对象x)指向祖父节点进入右旋转调整。

上面处理了如果父节点是祖父节点的左子节点的3种情况,第一种:新加入节点的父节点和它的兄弟节点都是红色,第二种新加入节点的父节点是红色,兄弟节点是黑色,它是父节点的右节点,第三种和第二种不同的地方是它是父节点的左节点。

下面看如果父节点是祖父节点右节点的情况:先拿到父节点的兄弟节点(祖父节点的左子节点),然后判断左子节点是不是红色,如果是红色,则把父节点,祖父节点的左子节点设置为黑色,祖父节点设置为红色,当前节点(原指向新加入节点)指向祖父节点,然后while循环继续调整。如下下图:

父节点红色兄弟节点红色调整方式

如果父节点的兄弟节点不是红色,判断自己是父节点的左节点还是右节点,如果是左节点,把当前节点指向父节点,然后以当前节点为基准进行右旋转,旋转完成后再进行颜色转换在进入左选择。如下图

这种直接进入旋转调整

如果自己是父节点的右子节点,则把父节点设置为黑色,祖父节点设置为红色,然后把当前节点指向祖父节点,进入while循环。

到这里为止,存在的集中可能都已经描述完成了。下面我们看看自旋的2种方式

右自旋的源码
左旋转源码

、我们根据上文中的判断条件分别看都是怎么做的。

1:首先如下图所示

完成一次左旋

继续调整如下图

先改变颜色,然后进入右旋
右旋过程先把p的left指向L的right
最后把P调整为L的right

这样一次调整就完成了。其实这里面需要注意的一点就是,如果新加入的节点的父节点是红色,祖父节点是黑色,且他是父节点的右节点,则先通过一次自旋调整为左节点的做节点红色冲突(这里不管新加入节点是祖父节点P的左子节点PL的任意节点,都需要先调整为P-PL-PL关系)。然后再依次从父节点开始改变颜色,然后右旋。从这里我们可以看到这一个过程的实现其实是,一个已经存在的树P(黑),PL(红),PR(黑)。新加入的节点PLL是PL的左子节点,则这里先把PL变成黑色,P变为红色,然后提升PL到P位置,把P调整为PL的PLR。这样完成了一次调整。文字描述晦涩,配合上图则非常直观。如果新加入节点PLR是PL的右子节点,则先通过自旋调整PL和PLR的关系,调整为PL是PLR的PLL,然后改变PLR的颜色为黑色,P为红色,然后旋转为P为PLR的右节点,PLR到P的位置,这样也完成了一次调整。这里不论图中L的右节点是不是null,其实都不影响整个过程。

下面用图来说明另外一种情况:即新加入的节点N是祖父节点P的右节点PR的子节点。如果是左子节点PRL,则先调整关系为顺线关系也就是P-PR-PR这种模式。

先调整冲突节点为P-PR-PRR模式
然后改变颜色并进行自旋调整
最后改变引用关系完成调整

红黑树的自旋调整基本都是基于这两个关系的。通过这样的调整,保证了红黑树的平衡。在concurrentHashMap中如果总个数超过64,且单个link超过8个则修改为红黑树。s

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容