HashMap是如何解决哈希冲突
哈希冲突
HashMap是一种键值对的存储数据结构,通过哈希函数把key映射到数组下标(bucket),哈希冲突就是不同的key经过哈希函数后得到相同的数组下标,因为数组有限,而key无限,所以冲突是不可避免的
HashMap常见的解决哈希冲突的方法
拉链法(Separate chaining/链地址法)
每个数组下标不直接存储单个元素,而是存储一个链表或链式结构,当key冲突时,放到这个链表中。
查找时,根据key的哈希值找到数组的下标,遍历链表,比较key是否相等
优点
- 简单易实现
- 当冲突少时,效率很高
缺点
- 链表过长时查找效率下降(后续Java8+用红黑树替换链表提升性能)
地址开放法(Open Addressing)
所有元素都存储在数组中,没有链表。当冲突发生时,寻找数组中下一个空槽位存放元素。常用探查方式:线性探查(下一个空槽依次查找)、二次探查(查找间隔平方递增,减少群聚现象)、双哈希(用第二个哈希函数计算步长)
优点
- 节约内存,不需要链表指针
缺点
- 数组负载因子过高时,插入/查找效率下降
再哈希法
当哈希冲突严重时,通过扩容数组+重新计算哈希值,把元素分散到更大的数组里,Java中的HashMap在达到负载因子0.75时会自动扩容(容量翻倍),并将链表/红黑树元素重新哈希到新数组
Java中HashMap的冲突处理(核心机制)
链表+红黑树
- Java8之前:链表存储冲突元素
- Java8之后:当链表长度>8且数组长度>=64->链表转换成红黑树,查找复杂度O(logn)
负载因子与扩容
- 默认负载因子0.75,超过就扩容并重新分布元素
哈希函数优化
- HashMap内部对key的hashCode做扰动处理,提高冲突分散性
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 JasmineRain's blog!
评论
