hash冲突及hash冲突的4种解决方案

哈希出现冲突的情况:

输入域与输出域不匹配:哈希函数的输入可以是任意长度的数据,组合无限,而哈希值的长度固定,输出域有限,根据鸽巢原理,必然会有不同输入映射到同一个输出值。

        (鸽巢原理:这是哈希冲突的根本原因。根据鸽巢原理(也称为抽屉原理),如果将 n+1n+1 个元素放入 nn 个容器中,则至少有一个容器包含多于一个元素。在哈希表中,这意味着当输入数据的数量超过哈希表的容量时,必然会发生冲突。)

哈希函数设计缺陷:理想的哈希函数应将输入数据均匀分布到输出域,但实际很难做到完美均匀,可能导致某些哈希值被频繁使用,从而引发冲突。

哈希表容量限制:哈希表大小固定,输入数据数量可能无限,当数据量超出哈希表容量,或负载因子(哈希表中存储的元素数量与哈希表大小的比值)过高,哈希表中的空闲位置减少,冲突概率就会增加。

特定数据模式:某些特殊的输入模式可能使哈希函数产生相同的哈希值,如哈希函数对输入的某些部分不敏感,具有相似部分的输入就可能映射到同一个哈希值。

恶意攻击:攻击者可能故意构造输入数据,使其产生相同的哈希值,引发哈希冲突,进行哈希洪水攻击。

hash冲突的4中解决方案:

1. 链地址法:将具有相同哈希值的元素用链表连接起来。如在HashMap中就采用了这种方法。

优点:

        处理冲突简单直观,不会出现堆积现象,即不同同义词不会相互干扰产生冲突因此平均查找长度较短;

        能适应数据总数频繁变化的场景,各链表上的结点空间可动态申请;

        装填因子可取α≥1,当结点较大时,增加的指针域空间可忽略不计;

        删除结点操作简单,只需删去链表上相应结点。

缺点:

        查询时需遍历链表,效率较低,存储动态导致查询跳转耗时多;

        在key - value可预知且无后续增改操作时,性能不如开放定址法;

        链表结构使序列化难度大;

2. 再哈希法:准备多个哈希函数,当第一个哈希函数计算出的key的哈希值冲突时,使用下一个哈希函数重新计算。

优点:

        能有效避免哈希值聚集的问题,让数据分布更均匀;

缺点:

        每次冲突都需重新计算哈希值,增加了计算时间成本;

3. 建立公共溢出区:把哈希表分为基本表和溢出表。基本表存储正常数据,一旦有元素与基本表发生冲突,就将其存入溢出表。

4. 开放定址法:key的哈希地址p = H(key)出现冲突时,以p为基础产生新的哈希地址p1,若p1仍冲突,继续以p1为基础产生p2等,直到找到不冲突的哈希地址pi来存储元素,公式为Hi=(H(key)+di)%mi = 1,2,…,n)。具体有以下三种方式:

        线性探测再散列:顺序查看下一个单元,di = 1,2,3,…,m - 1;

        二次(平方)探测再散列:在表的左右进行跳跃式探测,di = 1²,-1²,2²,-2²,…,k²,-k²k<=m/2);

        伪随机探测再散列:建立伪随机数发生器,以随机数为起点,di为伪随机数序列;

优点:

        数据容易序列化;

        若能预知数据总数,可创建完美哈希数列,提升查找效率;

缺点:

        为减少冲突,要求装填因子α较小,结点规模大时会浪费大量空间;

        删除节点操作复杂,不能简单置空,需做删除标记,否则会截断后续同义词结点的查找路径;

你可能感兴趣的:(哈希算法,散列表,算法)