散列冲突解决方案

散列冲突的解决办法:
1.开放地址法
(1)线性探测法:
就是一个公式:   H=(H0+D)%m
m:散列表的长度。D:一个增长的序列:1,2,3..........m-1   。  H0就是准备存入的Hash(key)。H:不冲突的散列码对应的位置。
假如散列表长为5,那么10%5=0,10这个值对应的散列码为0,就存储在散列表0的位置。如果进来了15,15%5=0,结果也为0,那么就和原来的散列值一比较,结果两个值不同,但是散列码相同就冲突了。那么就增加1,就是(10+1)%5=1,现在1这个位置没有元素,那么15这个散列值对应的散列码就是1.但是你会发现装入的元素越来越多的时候,就会出现,频繁的冲突,这个就是缺点。
缺点:
① 处理溢出需另编程序。一般可另外设立一个溢出表,专门用来存放上述哈希表中放不下的记录。此溢出表最简单的结构是顺序表,查找方法可用顺序查找。
② 按上述算法建立起来的哈希表,删除工作非常困难。假如要从哈希表 HT 中删除一个记录,按理应将这个记录所在位置置为空,但我们不能这样做,而只能标上已被删除的标记,否则,将会影响以后的查找。
③ 线性探测法很容易产生堆聚现象。所谓堆聚现象,就是存入哈希表的记录在表中连成一片。按照线性探测法处理冲突,如果生成哈希地址的连续序列愈长 ( 即不同关键字值的哈希地址相邻在一起愈长 ) ,则当新的记录加入该表时,与这个序列发生冲突的可能性愈大。因此,哈希地址的较长连续序列比较短连续序列生长得快,这就意味着,一旦出现堆聚 ( 伴随着冲突 ) ,就将引起进一步的堆聚。
(2)线性补偿探测法 
线性补偿探测法的基本思想是:
将线性探测的步长从 1 改为 Q ,即将上述算法中的 j = (j + 1) % m 改为: j = (j + Q) % m ,而且要求 Q 与 m 是互质的,以便能探测到哈希表中的所有单元。
【例】 PDP-11 小型计算机中的汇编程序所用的符合表,就采用此方法来解决冲突,所用表长 m = 1321 ,选用 Q = 25 。
(3)随机探测 
随机探测的基本思想是:
将线性探测的步长从常数改为随机数,即令: j = (j + RN) % m ,其中 RN 是一个随机数。在实际程序中应预先用随机数发生器产生一个随机序列,将此序列作为依次探测的步长。这样就能使不同的关键字具有不同的探测次序,从而可以避 免或减少堆聚。基于与线性探测法相同的理由,在线性补偿探测法和随机探测法中,删除一个记录后也要打上删除标记。
2.拉链法:
就是链表+数组
散列表的长度为数组的长度。实际就是Hash(Key)为H0,表长为m,不冲突的散列码的位置:H。
公式:H=H0%m
将具有相同散列码的散列值组成一个链表的形式。
在往HashSet存入元素的时候,它首先得调用hashCode方法得到元素对应的哈希码值,然后将哈希码值进行计算,算出元素在哈希表的位置。如果算出来的位置要是没有值,那么毫无疑问直接将元素添加到哈希表中。如果算出来的位置上有值,那么就得进行一下比较了,就调用equals方法进行比较一次,如果比较结果为真,那么元素相同,HashSet不允许元素重复,则就不让添加呗。如果比较结果为假,那么就添加进哈希表。
拉链法优点:①拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
②由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
③开放定址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
④在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放地址法构造的散列表,删除结点不能简单地将被删结 点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径。这是因为各种开放地址法中,空地址单元(即开放地址)都是查找失败的条件。因此在 用开放地址法处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记,而不能真正删除结点。
拉链法缺点:拉链法的缺点是:指针需要额外的空间,故当结点规模较小时,开放定址法较为节省空间,而若将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放定址法中的冲突,从而提高平均查找速度。
原文地址:https://www.cnblogs.com/chump-zwl/p/6946062.html