HashMap-链表与红黑树转换触发条件

article/2025/5/15 10:03:17

JDK1.8对HashMap进行了很多优化。

例如当一个槽位slot上的链表个数过多时,则会将链表转换为红黑树,以提高查询检索的效率。

访问节点方式:先找到节点所在的数组index索引位置,然后判断节点是什么结构进行遍历。

  • 节点结构是非树型(链表)结构,通过节点的next遍历链表。
  • 节点结构是树型(红黑树)结构,HashMap维护了2种节点之间的联系关系,分别是
  1. 链表方式:通过节点的next遍历链表。
  2. 红黑树方式:通过根节点root遍历红黑树。

一 链表->红黑树

树化阈值为8

static final int TREEIFY_THRESHOLD = 8;

最小树化容量值为64

static final int MIN_TREEIFY_CAPACITY = 64;

链表转化为红黑树需要满足2个条件

  1. 链表的节点数量(包括新增节点)大于等于树化阈值(查看源码可知,putVal方法是大于树化阈值,而其他方法是大于等于树化阈值)。
  2. HashMap的容量(Node数组的长度)大于等于最小树化容量值。

1.1 树化第一个条件

第一个条件:链表的节点数量(包括新增节点)大于等于树化阈值

HashMap触发判断第一个条件的位置主要有4个方法,分别是putVal方法、computeIfAbsent方法、compute方法、merge方法。

1.1.1 putVal方法

查看putVal源码可知,根据key判断是否存在节点。若是不存在,则创建节点并加入到HashMap中,返回null。若是存在节点,则直接替换节点的旧值,并返回旧值。

根据key找到在Node数组的index位置,然后若该位置有节点,且节点连接方式是链表,则遍历链表寻找是否有对应key的节点。若是没有,则创建新节点加入到链表中,并判断当前槽位slot的链表的数量(数量包括新增的节点)是否大于树化阈值,链表节点数量大于树化阈值才会进入下一个树化判断,如下图。

1.1.2  computeIfAbsent方法

computeIfAbsent方法如果根据key找到对应节点,且节点的值不为null,则直接返回旧值,不更新节点的值。如果找不到对应节点或节点的值为null,则根据调用mappingFunction参数的apply方法得到新value,若得到的新value值不为null,则替换掉存在节点的值或者新增值为新value的节点,返回新value。

若是新增节点,且节点连接方式为链表,则判断链表的节点数量(包括新增节点)是否大于等于树化阈值。若是满足,则进入下一个树化条件判断。

1.1.3 compute方法

compute方法根据调用的remappingFunction参数的apply方法得到新value。若key的节点存在,且新value不为null,则更新节点的值,若新value为null,则删除该节点。若是节点不存在,且新value不为null,新增节点,返回新value。

若是新增节点,且节点连接方式为链表,则判断链表的节点数量(包括新增节点)是否大于等于树化阈值。若是满足,则进入下一个树化条件判断。 

1.1.4 merge方法

merge方法若key的节点存在,且节点值不为null,调用的remappingFunction参数的apply方法得到新value,若节点值为null,则传入的valule为新value。若新value不为null,则更新节点的值,若新value为null,则删除该节点。若是节点不存在,且新value不为null,新增节点,返回新value。

若是新增节点,且节点连接方式为链表,则判断链表的节点数量(包括新增节点)是否大于等于树化阈值。若是满足,则进入下一个树化条件判断。

1.2 树化第二个条件

第二个条件:HashMap的容量(Node数组的长度)大于等于最小树化容量值

满足树化第一个条件后,调用treeifyBin方法判断是否满足第二个树化条件。 

若HashMap的node数组未初始化或者容量(node数组的长度)小于最小树化容量值,则不会将链表转换为红黑树,而是调用resize方法进行扩容操作。

若是node数组已初始化,且容量大于等于最小树化容量值,则将链表转换为红黑树。

二 红黑树->链表

非树化阈值为6

    static final int UNTREEIFY_THRESHOLD = 6;

红黑树转换为链表只需满足以下2个条件之一便可

  • 当删除红黑树的节点时,调用removeTreeNode方法。 在removeTreeNode方法中,判断如果根节点rootroot.rightroot.leftroot.lelt.left其中一个为空,则认为该红黑树的节点个数太少了,不必采用红黑树结构,调用untreeify方法将红黑树转化为链表结构。

  • 红黑树的节点数量小于等于非树化阈值。

当HashMap调用resize方法进行扩容时,如果slot槽位上的节点结构为红黑树,则调用节点的split方法重新分配节点在扩容后新数组的位置。

split方法中, 通过(e.hash & bit) == 0(根据key的hash找到数组的位置的一种方式)来判断节点是否在同一个槽位slot

  • 等于0,则表示该节点在扩容后的新数组的slot位置不变,也就是根据(n-1)&hash(n为扩容后的新数组的长度)找到新数组的index索引等于旧数组的index索引。
  • 若是不等于0,则表示该节点在扩容后的新数组的slot位置变了,也就是根据(n-1)&hash(n为扩容后的新数组的长度)找到新数组的index索引改变了,新索引等于旧数组的index索引加上旧数组的长度

通过(e.hash & bit) == 0公式拆分得到的loHead链表和hiHead链表。

  • 若是其中链表一个为空,则说明红黑树的所有节点在扩容后的数组index位置相同,则可直接将红黑树移到对应索引位置,不用维护红黑树的结构,因为结构没变化,还是一样的平衡结构。
  • 若是都不为空,则说明红黑树的节点分散了,平衡结构被破坏了,需要重新维护红黑树的平衡。
  • 拆分后的链表个数若小于等于非树化阈值,说明红黑树的节点个数少了,无需维护红黑树结构,调用untreeify方法将红黑树转化为链表结构。

HashMap的源码解读可参考

深入理解HashMap(一)hashmap所用算法、构造函数_热爱健体的程序猿的博客-CSDN博客_hashmap的算法

tableSizeFor的理解_zwangsheng的博客-CSDN博客_tablesizefor

链表转红黑树的原因?为什么阈值为8?_菜鸟猫喵喵的博客-CSDN博客_阈值为什么是8


http://chatgpt.dhexx.cn/article/B3nZZuDq.shtml

相关文章

9.HashMap里的红黑树是什么

1. 简介 红黑树是一种自平衡二叉查找树。它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用。在C STL中,很多部分(目前包括set, multiset, map,multimap)应用了红黑树的变体(SGI STL中的红黑树有一…

算法:什么是红黑树

红黑树的定义 红黑树的英文是“Red-Black Tree”,简称 R-B Tree。它是一种不严格的平衡二叉查找树。顾名思义,红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足这样几个要求&#x…

pygraphviz的安装与红黑树可视化

大家好,我是小小明,今天我将带大家安装pygraphviz,并通过它对红黑树这种数据结构进行可视化。 pygraphviz的安装与红黑树的可视化 安装graphviz 下载地址:http://www.graphviz.org/download/ windows平台下可以选择&#xff1…

到底什么是红黑树?

到底什么是红黑树? 首先,可以这么简单粗暴的理解,红黑树≈平衡的二叉排序树。 那么很显然,要想弄懂红黑树,得先明白什么是树、二叉树、二叉排序树、平衡树以及不平衡树。下面我们一个个来了解。 1.第一个问题&#x…

面试常问:什么是红黑树?

什么是红黑树? ———————————— 二叉查找树(BST)具备什么特性呢? 1.左子树上所有结点的值均小于或等于它的根结点的值。 2.右子树上所有结点的值均大于或等于它的根结点的值。 3.左、右子树也分别为二叉排序树。 下图…

红黑树简介

一、什么是红黑树 红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。 红黑树是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symme…

什么是红黑树?

一、红黑树的产生 1.二叉树 定义:二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的&…

说说什么是红黑树?

分析&回答 红黑树介绍 R-B Tree,全称是Red-Black Tree,又称为“红黑树”,红黑树就是一种平衡的二叉查找树,说他平衡的意思是他不会变成“瘸子”,左腿特别长或者右腿特别长。除了符合二叉查找树的特性之外&#xf…

漫画:什么是红黑树?(整合版)

前段时间,小灰发布了红黑树相关的文章,分成上下篇来讲解。 这一次,小灰把两篇文章做了整合,并且修正了红黑树删除部分的图片错误,感谢大家的指正。 ————— 第二天 ————— ———————————— 二叉查找…

抗性基因数据库CARD介绍

随着抗生素药物的发现及使用,越来越多的耐药菌株由此产生。而耐药菌株的发展则会增加疾病治疗的难度和成本,因此耐药微生物的研究则显得尤为重要。目前,通过对耐药基因的鉴定挖掘能够一定程度上帮助我们揭开耐药机制,为疾病的治疗…

关于 GIL

目录 GIL是什么GIL产生的原因如何避免受到GIL的影响什么时候会释放GIL锁互斥锁和Gil锁的关系 参考链接 python中的GIL详解 python面试不得不知道的点——GIL 《Python面试每日一题》之GIL Python GIL 是功能和性能之间权衡后的产物,它尤其存在的合理性&#xff0…

gin介绍

Gin的介绍与应用 Gin是一个golang的web框架,Gin像是一些常用函数或者工具的集合。具有快速灵活,容错方便等特点。Gin自身的net/http足够简单,性能也非常不错。 Gin的官网:https://github.com/gin-gonic/gin 安装前保证git和go都安…

gin_gorm

一、使用形式 1、引入gorm包 import "github.com/jinzhu/gorm" 2、导入数据库驱动 import _ "github.com/go-sql-driver/mysql"为了方便记住导入路径,GORM包装了一些驱动: import _ "github.com/jinzhu/gorm/dialects/mysq…

【GIC】配置GIC

本章介绍如何在裸机环境中启用和配置兼容GICv3的中断控制器。 目录 一、全局设置 二、单独PE设置 2.1 Redistributor配置 2.2 CPU接口配置 2.3 PE配置 三、SPI, PPI, SGI配置 3.1设置SPI的目标PE 附:寄存器介绍 附1:GICD_CTLR 附2:…

大寰AG-95夹爪指尖更换、结构示意图及通讯协议转换器说明

注意: 在对手爪进行任何操作之前,请先关闭机器人和夹持电源。 大寰AG-95夹爪指尖更换更换步骤: 1. 使用 M3 内六角螺丝刀卸下指尖螺丝,拆卸磨损的指尖。 2. 清洁手指件并彻底擦干。 3. 取出指尖上φ3x6 mm 定位销。 4. 将…

使用Landsat系列数据来检测喜马拉雅地区的冰湖溃决(Georg Veha等人,RSE,2018)

一、背景 这是一篇做冰湖溃决的文章,作者主要使用了random forest来检测喜马拉雅地区的冰湖溃决现象,这项成果发表在了Remote Sensing of Environment上。 文献连接:https://doi.org/10.1016/j.rse.2017.12.025 文献引用:Georg Ve…

App设计灵感之十二组精美的智能家居App设计案例

通过手机远程启动家里的各种家用电器,让我们回到家后可以享受到舒适的环境,这便是智能家居给我们带来的便利。 ① Smart Hub Application design by Ariuka ② Smart Home by Srgi Mi ③ Smart Home Mobile App by Ghulam Rasool ④ Smart Home Mobile …

基恩士KV8000通过HT3S-EIS-MDN网关与大寰机器人交换数据

一、概述 本文主要介绍使用HI-TOP网关 HT3S-EIS-MDN在基恩士KV8000 PLC和大寰RGI系列旋转抓手之间进行数据交换。 解决的问题:基恩士PLC KV8000监控和大寰RGI系列旋转抓手。 解决方法:使用HI-TOP网关 HT3S-EIS-MDN。基恩士KV8000支持EthterNet/IP协议…

CARD耐药数据库Linux使用

一、背景 关于耐药性有很多数据库可以使用,但是CARD的优势在于数据库较为准确,只有经过文章进行验证后的基因才会被记录 二、软件链接 软件github: GitHub - arpcard/rgi: Resistance Gene Identifier (RGI). Software to predict resistomes from p…