让星星⭐月亮告诉你,HashMap中红黑树TreeNode的split方法源码解读

31 篇文章 0 订阅
24 篇文章 0 订阅

PS:由于文档是我在本地编写好之后再复制过来的,有些文本格式没能完整的体现,故提供下述图片,供大家阅览,以便有更好的阅读体验:
在这里插入图片描述
在这里插入图片描述
HashMap中红黑树TreeNode的split方法源码解读
分析HashMap$TreeNode(既是树又是链表)的split方法的源码,会发现主要分两部分操作:

  1. 数据从旧数组转移到新数组上来時,旧数组上的数据会根据(e.hash & oldCap) 是否等于0,重新rehash计算其在新数组上的索引位置,分成2类:
    ① 等于0时,则将该树链表头节点放到新数组时的索引位置等于其在旧数组时的索引位置,记未低位区树链表lo开头-low;
    ② 不等于0时,则将该树链表头节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度,记为高位区树链表hi开头high(具体推导过程,详见《HashMap扩容时的rehash方法中(e.hash & oldCap) == 0源码解读》).

  2. 当红黑树被split分割开成为两个小红黑树后:
    ① 当低位区小红黑树元素个数小于等于6时,开始去树化untreeify操作;
    ② 当低位区小红黑树元素个数大于6且高位区红黑树不为null时,开始树化操作(赋予红黑树的特性)
    具体,详见下述的源码解析:
    1./HashMap$TreeNode的split()方法/
    方法概述:将红黑树从旧数组转移到新数组
    /
    *
    * Splits nodes in a tree bin into lower and upper tree bins,
    * or untreeifies if now too small. Called only from resize;
    * see above discussion about split bits and indices.
    *
    * @param map the map
    * @param tab the table for recording bin heads
    * @param index the index of the table being split
    * @param bit the bit of hash to split on(其实就是旧数据的容量大小oldCap)
    */
    final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
    TreeNode<K,V> b = this;
    // Relink into lo and hi lists, preserving order
    TreeNode<K,V> loHead = null, loTail = null;
    TreeNode<K,V> hiHead = null, hiTail = null;
    int lc = 0, hc = 0;
    for (TreeNode<K,V> e = b, next; e != null; e = next) {
    next = (TreeNode<K,V>)e.next;
    e.next = null;
    if ((e.hash & bit) == 0) {//区分高低位树链表的核心算法
    if ((e.prev = loTail) == null) //低位尾部标记为null,表示还未开始处理,此时e是第一个要处理的低位树链表节点,故e.prev等于loTail都等于null.
    loHead = e; //低位树链表的第一个树链表节点
    else
    loTail.next = e;
    loTail = e;
    ++lc; //低位树元素个数计数
    }
    else {
    if ((e.prev = hiTail) == null)
    hiHead = e; //高位树链表的第一个树链表节点
    else
    hiTail.next = e;
    hiTail = e;
    ++hc; //高位树链表元素个数计数
    }
    }

        if (loHead != null) {//低位树链表不为null
            if (lc <= UNTREEIFY_THRESHOLD) //低位树链表元素个数若小于等于6
                tab[index] = loHead.untreeify(map); //开始去树化操作(就是将元素ThreeNode节点 类型都替换成Node节点类型),具体方法源码详见第2点
            else {
                tab[index] = loHead;
                if (hiHead != null) // (else is already treeified) //若高位树链表头节点为空,说明还未处理完高位,还不能开始树化操作
                    loHead.treeify(tab); //低位树链表元素个数若大于6且高位树链表头节点不等于null,开始将低位树链表真正树化成红黑树(前面都只是挂着TreeNode的名号,但实际只是链表结构,还没包含红黑树的特性,在这里才赋予了它红黑树的特性) 具体方法源码详见[《HashMap之链表转红黑树(树化 )-treefyBin方法源码解读》](https://editor.csdn.net/md/?articleId=106801839)
    

}
}
if (hiHead != null) { //原理同低位树链表处理,不再赘述
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}
2. /HashMap$TreeNode的untreeify ()方法/
方法概述:将链表的TreeNode类型转换成Node节点类型
/
*
* Returns a list of non-TreeNodes replacing those linked from
* this node.
*/
final Node<K,V> untreeify(HashMap<K,V> map) {
Node<K,V> hd = null, tl = null;
for (Node<K,V> q = this; q != null; q = q.next) {
Node<K,V> p = map.replacementNode(q, null); //将节点的类型转换成Node链表节点类型, 具体方法源码详见第3点

            if (tl == null)
                hd = p;
            else
                tl.next = p;
            tl = p;
        }
        return hd;
    }
  1. /*HashMap的replacementNode ()方法/
    方法概述:将节点p的类型转换成Node链表节点类型
    // For conversion from TreeNodes to plain nodes
    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
    return new Node<>(p.hash, p.key, p.value, next); //创建Node类型节点并返回
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylanu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值