hash冲突

  • 当做hash计算时 A与B计算出来的值都是C,这就发生了hash冲突。
  • 解决的办法如下
  • 开放定址法
    keyA=hash(A);出现冲突时,我们以keyA为基础再进行hash计算,
    例如:keyA1 = hash(A+keyA);公式定义如下
    为产生冲突的key获取一个地址序列
    H1,H2,H3....Hs;(1Sm1)H_1,H_2,H_3....H_s;( 1\leq S \leq m-1)
    H0=hash(key);H_0 = hash(key);
    Hi=(hash(key)+di)MODm;H_i = (hash(key)+d_i)MODm;
    i=1,2,3,s i=1,2,3,s
    这里的m,是表的长度tablesize
    怎么理解呢,就是在原有的hash值基础上增加一个值di再进行取模,避免与之前的key出现冲突,
    其中 di有几种取值方式。
    1.线性探索即累计+1的方式{1,2,3,4…m-1}
    2.平方探索
    f(i)=i2f(i)=i^2
    Hi=(hash(key)+f(i))m;H_i=(hash(key)+f(i))m;
    平方探测因为是平方探测,因此出现冲突的概率依然很高,
  • 再hash算法是重新建立一个hash函数,计算hash值
  • 公共溢出区 就是将hash表分为两个表一个存正常hash的值,另一个表存储发生冲突的值。

不过开放定址法这种方式在位置都被占的情况下就没有办法了。因为不论怎么探索,都会hash冲突。怎么办?
于是就有了拉链法了
拉链是啥?
看图
hash冲突
大概结构就是这个样子,hash表位置冲突后,不是重新定址,而是直接冲突值存到这个位置,例如图中1的位置冲突的value为31,21,11。此时1的位置存储的是一个指针指向最先存入的value位置,以此类推,没次冲突时将新的值添加下一个节点。
此方法有啥好处?
1 上面说了为了解决多次hash冲突,而且删除节点时也方便了。
2 节点删除也更容易了
3 查询时间缩短(因为不用重新定址,一步就能定位到具体位置,在根据位置查询数据)
缺点呢?
如果有一个人点碰撞值,会导致一条很长的链表出现,因为单链表,检索需要一个个查找
所以在jdk1.8以后hashmap替换了链表,使用了红黑树。
触发链表转红黑树的负载因子是8(同一个hash表位置冲突值满8个也不容易)
删除节点时,红黑树转成链表的因子数是6

相关文章: