采用双散列法进行元素的插入与搜索时,要求rehash(key)这个函数值与散列表容量tablesize互质。
个人认为原因如下:
1.(关于rehash()函数简单介绍)
rehash()函数的作用:当在散列表中搜索key关键码时,首先用hash()函数计算hash(key)的值H0,找到下标为H0的位置,若此位置上已有其他元素,则称发生冲突,此时用rehash()函数计算rehash(key)的值r(此值还要求小于tablesize),使Hi=(H(i-1)+r)%tablesize(寻找下一个位置)(tablesize代表散列表的总容量)重复此操作直到下标为h的位置满足条件(若在进行插入操作,则h位置为空即满足条件;若在进行搜索操作,则h位置的元素与key值相同即满足条件)。
2.(需要用到的公式)
(A+B)%m=(A%m+B%m)%m。(证明详见文末)
3.(核心部分:反证)
现有一散列表s[m](容量为m)。假设现在需要对key值进行搜索,那么按照标准散列表步骤,先计算h0=hash(key),此时如果s[h]的值与key值不相等,那么就该rehash()上场了:计算r=rehash(key)(r是小于tablesize的)。若r与m不互质,即存在公共因数(除了1),不妨记作:
r=u*q; m=v*q; (显然v<m)
令h1=(h0+r)%m,
那么h2=(h1+r)%m=((h0+r)%m+r)%m=((h0+r)%m+r%m)%m=(h0+2*r)%m(这里用到了第二步的公式,其中r=r%m是因为r小于m)。以此类推,hn=(h0+n*r)%m。
如果运气很坏,始终没有能够搜索到key值,那么最多需要遍历m次(也就是把散列表全部搜索一遍),
那么在r和h0有公因数的情况下,能否做到遍历散列表中所有的位置呢?
答案是:不能。
根据之前得到的hn=(h0+n*r)%m。当n=v时(v为m的因数),hn=(h0+v*u*q)%m=h0%m+v*q*u%m=h0,说明当遍历了v个位置后,hn又回到了h0,如果继续遍历下去,可以想象应该是之前遍历的循环,也就是说这种遍历最多只能遍历v个位置,而相应地则有m-v个位置永远无法被遍历到,那么显然这种方法是存在问题的,故而r和m不能有公因数。
4.(正证)
由上可知,hn=(h0+n*r)%m。若m与r互质,那么只有当n=m时,hn=h0%m+m*r%m=h0,也就是说,恰好遍历m个位置才会回到h0,这样就可以实现遍历表中所有的位置,岂不妙哉。
5.(关于第二步中公式的证明)
设A%m=a2; B%m=b2;
则A=a1*m+a2; B=b1*m+b2.
(A+B)%m=(a1*m+a2+b1*m+b2)%m=((a1+b1)*m+(a2+b2))%m=(a2+b2)%m=(A%m+B%m)%m。(证明完毕)