HashMap是怎么解决哈希冲突的

简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的:

  1. 使用拉链法(使用链表)来链接拥有相同hash值的数据
  2. 使用新hash函数(2次扰动函数)来降低哈希冲突的概率,使得数据分布更平均
  3. 引入红黑树进一步降低遍历的时间复杂度,使得遍历更快

什么是哈希函数?

Hash,一般翻译为“散列”,也有直接音译为“哈希”的,这就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值(哈希值);这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

所有散列函数都有如下一个基本特性:根据同一散列函数计算出的散列值如果不同,那么输入值肯定也不同。但是,根据同一散列函数计算出的散列值如果相同,输入值不一定相同

什么是哈希冲突?

当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做哈希冲突(哈希碰撞)。

HashMap的数据结构:

在Java中,保存数据有两种比较简单的数据结构:数组和链表。
数组的特点是:寻址容易,插入和删除困难;
链表的特点是:寻址困难,但插入和删除容易;
所以我们将数组和链表结合在一起,发挥两者各自的优势,使用一种叫做链地址法(拉链法)的方式可以解决哈希冲突

HashMap是怎么解决哈希冲突的_第1张图片

这样我们就可以将拥有相同哈希值的对象组织成一个链表放在hash值所对应的bucket(即数组中的一个元素)下,但相比于hashCode返回的int类型,我们HashMap初始的容量大小DEFAULT_INITIAL_CAPACITY = 1 << 4(即2的四次方16)要远小于int类型的范围,所以我们如果只是单纯的用hashCode取余来获取对应的bucket这将会大大增加哈希碰撞的概率,并且最坏情况下还会将HashMap变成一个单链表,所以我们还需要对hashCode作一定的优化

通过上面的链地址法(使用散列表)和扰动函数我们成功让我们的数据分布更平均,哈希碰撞减少,但是当我们的HashMap中存在大量数据时,加入我们某个bucket下对应的链表有n个元素,那么遍历时间复杂度就为O(n),为了针对这个问题,JDK1.8在HashMap中新增了红黑树的数据结构,进一步使得遍历复杂度降低至O(logn);

总结HashMap是怎么解决哈希冲突的:

简单总结一下HashMap是使用了哪些方法来有效解决哈希冲突的:

  1. 使用拉链法(使用链表)来链接拥有相同hash值的数据;
  2. 使用新hash函数(2次扰动函数)来降低哈希冲突的概率,使得数据分布更平均;
  3. 引入红黑树进一步降低遍历的时间复杂度,使得遍历更快;

你可能感兴趣的:(数据结构和算法,面试,javase,哈希算法,散列表,数据结构)