跳至主要內容

哈希冲突怎么解决

ZnyoungJava集合哈希

下面假设hash=(x) -> x/2,hash表的长度为10,x可取5,6等,此时hash(5)=hash(6)=3,产生冲突

开放定址法

开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。

也被称为再散列法,当出现hash冲突的时候,会将上一次hash的结果和增量序列相加,然后对hash表的长度取模,进行再散列;如当3=hash(5) =hash(6)时,此时hash(6)就需要利用开放定址法解决冲突:hash(6)=(3+d)%length = p1 (d为增量序列)
其中,增量序列的获取方式有三种:

  • 线性探测再散列:当发生冲突的时候,顺序查看,直到能够找到空位;d = 1/2/3..../length-1
  • 二次探测再散列:当发生冲突时,d正负跳跃,比较灵活;d = 1/-1/2/-2/...../(length-1)/2
  • 伪随机探测再散列:d取伪随机数
    此时,对于hash(5)和hash(6)的冲突来说,拿线性探测再散列举例:hash(6)=(3+1)%10=4

链地址法

将哈希表的每个单元作为链表的头结点,所有哈希地址为i的元素构成一个同义词链表。即发生冲突时就把该关键字链在以该单元为头结点的链表的尾部。

HashMap采用该方法,当出现hash冲突的时候,会使同一个hash的所有值形成一个链表。查询的时候,首先通过hash定位到该链表,然后再遍历链表获得结果。
此时,对于hash(5)和hash(6)的冲突来说,则会在hash表的第三个节点形成链表,如:hash[3]->5->6
优点:

  • 处理冲突简单
  • 适合经常插入和删除的情况下
  • 适合没有预定空间的情况

缺点:

  • 当冲突较多的时候,查询复杂度趋近于O(n)

再哈希法

当哈希地址发生冲突用其他的函数计算另一个哈希函数地址,直到冲突不再产生为止。

当发生冲突时,需要更换hash函数,如当hash(5)=hash(6),此时hash(6)就需要切换成hashNew(6)才行,直到新的hash函数没有冲突

建立公共溢出区

将哈希表分为基本表和溢出表两部分,发生冲突的元素都放入溢出表中。

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

上次编辑于:
贡献者: 麦正阳