三、JAVA集合:TreeMap红黑树深度解析

JAVA集合:TreeMap红黑树深度解析

规则:

每个节点都有颜色(红或黑);根节点必须是黑色的;叶子节点(null节点)是黑的,即每个节点都有两个子节点(其中一个或者两个可能是null节点);相连节点不能都是红色(红色节点的父节点和子节点必须为黑色);任意节点到它所有的叶子节点的路径都含有相同的黑色节点的数量。

结构:

u=1815023873,679902369&fm=173&s=01307533074A5564087DA1DA0000C0B2&w=585&h=291&img.JPEG

.

u=2800488545,20422015&fm=173&s=65B6A97697E648A14ADCB0D00000C0B3&w=640&h=328&img.JPEG

.

【引申规则:根据规则4和5,如果一个节点只有一个子节点,那么这个子节点肯定是红色的并且没有子节点。(如上图的22节点和65节点)】

基本方法:

获取节点颜色,叶子节点(null节点)的颜色是黑色

.

变化:

 

为了保证规则5成立,插入节点的颜色总是红色的,但这时候可能会造成规则4不成立,就需要进行调整,红黑树有两种调整操作:

变色(改变节点的颜色)旋转(左旋转和右旋转)

左旋转示意图(对节点E左旋转)

b812c8fcc3cec3fd7142a1b9dd88d43f869427f9.jpg

.

u=653612766,99333916&fm=173&s=00207432990EC54D50D5A5DA000090B1&w=587&h=481&img.JPEG

.

右旋转示意图(对节点S右旋转)

d4628535e5dde711db83453aacefce1b9c1661ac.jpg

.

u=1332775663,4145944265&fm=173&s=00106D32191A644D4E7580DA0000C0B2&w=587&h=365&img.JPEG

.

put方法:

u=4193206472,1858101172&fm=173&s=00707532D90FE44D587500DA0000D0B2&w=585&h=648&img.JPEG

.

u=2625641612,343488502&fm=173&s=88207432D90EC44D4C55A0DA0000C0B3&w=590&h=657&img.JPEG

.

fixAfterInsertion插入新节点之后的调整函数(重点):

u=930110008,2719372661&fm=173&s=81707133910FF54D1C74A1DA000050B0&w=587&h=698&img.JPEG

.

u=4181927072,1934070535&fm=173&s=D9203573990FC44D4E5D80DA0000C0B1&w=579&h=710&img.JPEG

.

u=194798867,3420824598&fm=173&s=49263572194A704D40ED81DB0000C0B1&w=607&h=403&img.JPEG

.

示例:

以下图红黑树为例

u=1489782255,2312134937&fm=173&s=6DF6A956176740A214F0F0CA0000C031&w=640&h=341&img.JPEG

.

现在我们要增加一个节点50,放在节点47的右子树上。

u=634993430,1401661011&fm=173&s=00B6683217864EE21CE5F4D800005031&w=640&h=380&img.JPEG

.

新增节点和父节点冲突,叔父节点是红色的,进行变色操作,把父亲节点和叔父节点都变成黑色,祖父节点变成红色,然后再对祖父节点进行调整。

u=2068446123,1352754508&fm=173&s=841074334B624D205C7524DA0000C0B2&w=585&h=151&img.JPEG

.

u=3009035616,901483076&fm=173&s=6D26AD5617864EE01AF0F4DB00008031&w=640&h=376&img.JPEG

.

叔父节点y是黑色的,并且x是右孩子,先进行左旋转,把红色节点转移到左分支。

u=498480819,2517410478&fm=173&s=002874324B63472408FC81DA0000C0B2&w=586&h=108&img.JPEG

.

u=166147283,1762407830&fm=173&s=20B668321F824ED21CF0F0D800008033&w=640&h=376&img.JPEG

.

再把x的父节点变黑,祖父节点变红,然后把祖父节点右旋转。

u=2846515347,1754975461&fm=173&w=584&h=85&img.JPEG

.

u=941963753,3643198662&fm=173&s=20B768321D667A8204F0DCCA0000B032&w=640&h=315&img.JPEG

.

 

最多两次旋转即可解决冲突。

delete方法:

u=1751161671,3791158966&fm=173&s=98207533890EE44D5C7580DA0000C0B3&w=599&h=698&img.JPEG

.

u=487266915,248596956&fm=173&s=00707433490EE44D4CDD81DA0000C0B2&w=585&h=709&img.JPEG

.

u=870284534,843011199&fm=173&s=48A03C724D666D201CFCC0DA0000C0B3&w=585&h=149&img.JPEG

.

successor方法(查找继承者):

当需要删除的节点有两个孩子节点时才调用此方法。即右孩子节点 != null

u=3414171678,4138801192&fm=173&s=81207C32990EE44D08DD81DA000050B3&w=588&h=525&img.JPEG

.

fixAfterDeletion删除节点的调整函数(重点)

 

算法思想:我们要删除一个黑色节点,这会破坏规则5,调整有3种情景:

如果兄弟节点是红色的,经过变色旋转,在x节点上面增加一个红色的父亲节点,并且不破坏其他分支的黑色节点数量。兄弟节点是黑色的,如果兄弟节点的子节点都是黑色的,直接把黑色节点变红,即减少兄弟分支的黑色节点数量,然后对其父节点进行调整;兄弟节点是黑色的,但其有红色的孩子节点,不能直接变红。如果左孩子是红色节点,经过变色和右旋转把红色节点移到右边。此时再经过变色,并对x的父节点进行左旋转,在x节点的上面增加一个黑色节点,并且不破坏其他分支的黑色节点数量,调整结束。

u=317882953,229424210&fm=173&s=89207532990FE54D5845E0DB0000C0B2&w=591&h=698&img.JPEG

.

u=2885377522,1565618747&fm=173&s=D8203D72990EC54D0C7DE0DB0000C0B1&w=585&h=697&img.JPEG

.

u=3852684356,2155523304&fm=173&s=C8203472D90FD74D0CF5A1DA000080B2&w=585&h=677&img.JPEG

.

示例:

删除的节点只有一个子节点(删除390),根据上面的引申规则,这个节点肯定是黑色,子节点是红色

u=1556551050,2525275837&fm=173&s=A59EA7769536CE310265F0FE0200E033&w=640&h=170&img.JPEG

.

删除红色的节点并且没有子节点(删除833)

u=3790487427,2792102714&fm=173&s=A59E257F9DE66C01426DD8EA0200E032&w=639&h=210&img.JPEG

.

 

删除黑色的节点并且没有子节点(删除22)

兄弟节点是红色的情况

u=2859008606,2115086914&fm=173&s=E516AD76976744A04AECB8D80000F0B1&w=640&h=337&img.JPEG

.

变色+旋转,给x节点增加一个红色的父亲节点

u=3357971112,455643177&fm=173&s=801074324B6345241EFDA5DA000080B2&w=580&h=153&img.JPEG

.

u=2597189961,408157514&fm=173&s=48A6387217664EA20CD0D0CA000070B3&w=640&h=355&img.JPEG

.

此时x的新兄弟节点是黑色,并且孩子节点全是黑色(叶子节点是黑色的),把兄弟节点变色,然后x指向父节点,while循环继续调整。

u=621406996,3558688021&fm=173&s=81307C324D226D20085DA0DB0000C0B2&w=589&h=112&img.JPEG

.

u=719835157,3242136635&fm=173&s=00B678321F664E820CF4D0CA0000C0B3&w=640&h=321&img.JPEG

.

节点是红色,跳出循环。循环外把该节点变黑。

.

u=3949836158,2533916863&fm=173&s=4B26386217664EA20CD4C0CA0000E0B1&w=640&h=340&img.JPEG

.

方法返回后,deleteEntry方法把22节点删除,整个过程结束。

u=2935045805,579943743&fm=173&s=001264334B624D2048F5A4DA000080B2&w=595&h=169&img.JPEG

.

u=4029364134,3841650052&fm=173&s=4BA638623F665E8208D4C0DA0000E0B1&w=640&h=322&img.JPEG

.

 

兄弟节点是黑色的情况

上面是旋转变化过程中其实已经遇见了这种情况,并且兄弟节点的孩子节点全是黑色,可以直接变色处理,下面来看一下,兄弟节点是黑色,并且有孩子节点是红色的情况

继续上面的红黑树,下面删除65节点

u=156281086,2041357410&fm=173&s=4536A97617667EA25EDC30DA0000C0B1&w=640&h=332&img.JPEG

.

兄弟节点是黑色,并且有红色的孩子节点,针对x是左孩子的情况下,如果红色节点是左孩子,需要通过旋转操作移到右边

u=1691756620,3457962246&fm=173&s=041064324B626D204AFD04DA0000C0B2&w=586&h=154&img.JPEG

.

u=2726074775,455513436&fm=173&s=6516A9767D667E825AFC20DA000010B2&w=640&h=319&img.JPEG

.

然后再进行变色旋转操作,给x节点增加一个黑色的父节点。x = root结束循环。

u=308258530,3096298264&fm=173&s=8112E0334B626D20585D80DA000080B2&w=589&h=133&img.JPEG

.

u=637715916,1489885511&fm=173&s=4BA638621D67748208DC90DA0000C0B3&w=640&h=313&img.JPEG

.

 

方法返回,deleteEntry方法把65节点删除,整个过程结束。

 

删除节点有两个孩子节点的情况。

u=1301735562,3841721997&fm=173&s=4BA63862176776A25CDC90DA0000C0B3&w=640&h=341&img.JPEG

.

删除节点55,该节点有两个孩子节点,deleteEntry方法中会查找继承者节点,即图中的65节点,把65节点的key和value赋值给55节点,然后转化为删除65节点。

u=1746623288,3289376412&fm=173&s=88207C324B6669204A7500DA0000C0B2&w=581&h=154&img.JPEG

.

u=4113103640,4148289898&fm=173&s=4B263862176776A24AFCA0DA000080B3&w=640&h=348&img.JPEG

.

 

因为继承者节点没有左孩子节点,所以这个问题又变成了删除一个孩子节点或者无孩子节点的问题。(参照上面)

OK,至此红黑树的分析就结束了,希望大家给予意见!

转载于:https://my.oschina.net/u/3933814/blog/2244575

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值