解决哈希冲突的常用方法

要了解 Hash 冲突,那首先我们要先了解 Hash 算法和 Hash 表。

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

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

所谓 hash 冲突,是由于哈希算法被计算的数据是无限的,而计算后的结果范围有限,所以总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。

通常解决 hash 冲突的方法有 4 种。

开放定址法,也称为线性探测法

基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p1为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。

再哈希法

这种方法是同时构造多个不同的哈希函数:

Hi=RH1(key)  i=1,2,…,k

当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

链式寻址法

这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

建立公共溢出区

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

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

你可能感兴趣的:(Java,哈希算法,算法,java)