【Java面试小短文】HashMap是如何解决Hash冲突的?

本文介绍了Hash算法的概念,即通过散列函数将任意长度的输入转化为固定长度的输出。Hash表,又称散列表,利用hash函数快速定位数据。在HashMap中,通过链式寻址法解决Hash冲突,当链表长度超过8且数组长度大于等于64时,会转为红黑树以优化查询效率。此外,文章还提及了开放寻址法、再哈希法等其他解决冲突的方法。

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

欢迎关注Java面试系列,不定期更新面试小短文。欢迎一键三连!

什么是Hash算法?

  Hash 算法,就是把任意长度的输入,通过散列算法,变成固定长度的输出,这个输出结果是一个散列值。

什么是Hash表?

  Hash 表又叫做“散列表”,它是通过 key 直接访问在内存存储位置的数据结构, 在具体实现上,我们通过 hash 函数把 key 映射到表中的某个位置,来获取这个位置的数据,从而加快查找速度。如图:

HashMap是如何解决Hash冲突的?

  HashMap底层是采用数组结构来存储数据元素,数组的默认长度是16,当我们通过put方法去添加数据的时候,HashMap会根据keyhash值进行取模运算,最终把这样一个值保存到数组的指定位置。

  但是这样的设计方式会存在hash冲突的问题,也就是两个不同的hash值的key,取模后会落到同一个数组下标,所以HashMap引入了一个链式寻址法来解决hash冲突的问题。也就是说对于存在冲突的keyHashMap把这些key组成一个单向链表,然后采用尾插法把这样一个key保存到链表的一个尾部,另外,为了避免链表过长导致查询效率下降,所以当链表长度大于8并且数组长度大于等于64的时候,HashMap会把当前链表转换为红黑树,从而去减少链表数据查询的时间复杂度来提升查询效率。

解决hash冲突的方法有很多,比如

  1. 链式寻址法。是一种非常常见的方法,简单理解就是把存在 hash 冲突的 key, 以单向链表的方式来存储,比如 HashMap 就是采用链式寻址法来实现的。

如图,像这样一种情况,存在冲突的 key 直接以单向链表的方式进行存储。

  1. 开放寻址法,也称为线性探测法。就是直接从冲突的数组位置向下去寻找一个空的数组下标,进行数据的存储,在ThredLocal里面有使用到这个线性探测法。

  如图:像这样一种情况,在 hash 表索引 1 的位置存了一个 key=name,当再次添加 key=hobby 时,hash 计算得到的索引也是 1,这个就是 hash 冲突。而线性探测法就是按顺序向前找到一个空闲的位置来存储冲突的 key

  1. 再哈希法。如果某个hash函数产生了冲突,那么再用另外一个hash函数进行计算,一直计算直到不再产生冲突。这种方式会增加计算时间,性能影响较大。比如像布隆过滤器就采用了这种方法。

  2. 建立公共溢出区。把 hash 表分为基本表和溢出表两个部分,把存在冲突的key统一放在一个公共溢出区里面进行存储。

  综上,HashMapJDK1.8 版本中,通过链式寻址法+红黑树的方式来解决 hash 冲突问题,其中红黑树是为了优化 Hash 表链表过长导致时间复杂度增加的问题。当链表长度大于 8 并且 hash 表的容量大于等于 64 的时候,再向链表中添加元素就会触发转化。


欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

砖业洋__

你的鼓励是我持续写作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值