HashMap之put详解(二)

本文详细探讨HashMap中红黑树的插入再平衡过程,包括左旋、右旋操作,以及如何通过HashMap.TreeNode::moveRootToFront确保根节点位于table[i]。文章通过实例解释了红黑树的特性及插入可能导致的不平衡情况,并展示了再平衡的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 导读

本次主要分享HashMap中红黑树插入后再平衡的过程, 主要内容如下:
.1 什么是红黑树;
.2 左旋与右旋;
.3 HashMap红黑树的再平衡过程;

2. 什么是红黑树

为后面内容做铺垫(如果对此部分内容熟悉可直接跳过), 先简单介绍下红黑树:
红黑树是一棵二叉树, 且是一棵自平衡二叉树, 到这里, 我们可以知道红黑树具有:
.1 除根节点外, 每个节点都有其父节点, 可以有两个子节点;
.2 比当前节点大是右节点, 小的是左节点;
除了上面的特性以外, 红黑树还有其自身的特性:
.1 节点是红色或黑色;
.2 根是黑色;
.3 所有叶子都是黑色(叶子是NIL节点;
.4 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点;)
.5 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点;
下面是一棵典型的红黑树:

那我们以上图为基准, 来看红黑树插入的情况:
.1 插入节点是12:
在这里插入图片描述

这种情况是比较理想的情况, 完全符合红黑树的特性, 就不需要再平衡;
我们来看下插入节点是7的情况:
.2 插入节点是7:
在这里插入图片描述

case 1: 7刚插入为红, 违反第四点特性;
case 2: 将父节点置黑, 违反第五点特性;
case 3: 将祖父节点置红, 然后绕祖父节点左旋, 红黑树即平衡;

.3 插入的节点是23:
在这里插入图片描述

case 1: 23刚插入, 违反特性4;
case 2: 绕22左旋, 22变成23的左子节点;
case 3: 将23置黑, 25置红, 绕25右旋, 红黑树重新平衡;

通过上面3个例子, 我们可以看到需要重新平衡红黑树的特征颜色:
case 1:
在这里插入图片描述

.1 父节点是红色, 那么把新节点置为黑色, 然后绕父节点左旋;
.2 这时因为祖父节点也是黑色的, 违反特性5, 我们还要做处理;
.3 我们把祖父节点置为红色, 然后绕祖父节点右旋, 红黑树重新平衡;

case 2:

case1有种特殊情况:存在叔叔节点;
.1 这时候只要把祖父节点置为红色, 父节点和叔叔节点置为黑色;
.2 用祖父节点再往上判断即可;

case 3:

这种情况就是case1的镜像, 那么操作也是按case1的镜像操作来即可:
.1 新节点置黑, 绕父节点右旋;
.2 祖父节点置红, 绕新节点左旋, 红黑树重新平衡;

3. 左旋与右旋

前面一直在用到左旋与右旋操作, 那么什么是左旋与右旋呢?

左旋是把父节点变成右子节点的左子节点的过程;
右旋是左旋的镜像操作: 父节点变成左子节点的右子节点的过程;

我们来看下HashMap.TreeNode::rotateLeft是如何处理的:

.1 要进行左旋的节点p必须要有右子节点r;
.2 如果r有左子节点rl, 那么rl要变为p的右子节点;
.3 如果p是根节点了, 那么r需要变为黑色, 这也是左旋过程中唯一的变色动作;

右旋其实是左旋的镜像动作, 这里就不做赘述了;

4. HashMap红黑树的再平衡

HashMap.TreeNode::balanceInsertion代码较长, 我们用流程图来说明:

HashMap.TreeNode::balanceInsertion的主要流程是:
.1 先把待插入节点x置为红色;
.2 遍历当前红黑树, 如果待插入节点已经是根节点了, x置黑, 直接返回;
.3 x的父节点xp是黑色节点, 直接返回;
.4 x的父节点是根节点, 直接返回;
.5 xp是xp的父节点xpp的左子节点, 且叔叔节点xppr存在, xppr为红色, 将xp和xppr置为黑色, xpp置为红色, 然后再次循环(循环时x变成了当前的xpp);
.6 xppr是黑色的, 且x是右节点, 绕xp左旋, 把xp变成x的左子节点;
.7 x经过上一步变化后变成了根节点(此时x已经变为黑色), 直接返回;
.8 x不是根节点, 先把x变黑, 再把xpp置红, 再以xpp进行右旋;
.9 x位于右子树的平衡过程是左子树的镜像过程, 请参考上面的5-8步;

可以看到红黑树的再平衡过程会变更根节点, 而HashMap的特性要求table[i]必须是二叉树的根节点, 那么HashMap是如何保证再次平衡过后的红黑树的root一定位于table[i]的呢?

5. HashMap.TreeNode::moveRootToFront

HashMap.TreeNode::moveRootToFront这个方法保证了平衡过后的红黑树的根节点一定位于首节点;

看示意图可得知, moveRootToFront()的作用就是将root摘出来, 将其放到首节点;

本期的分享就是这些了, 上面内容如有不足之处, 欢迎指正;
如果看了对你有帮助, 烦请点赞转发, 感谢;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值