几乎是标题:我正在散列一堆名字(10000-ish),有些正在输出为负数。 (表格大小为20011)。
有问题的哈希函数是:
public static long hash2 ( String key ){
int hashVal = 0;
for( int i = 0; i < key.length(); i++ )
hashVal = (37 * hashVal) + key.charAt(i);
return hashVal % 20011;
}
我挖了一下,我想我必须要做一些事情“环绕”。但我不知道如何去做。
答案 0 :(得分:2)
这是Integer Overflow
的明显案例。正如您在问题中提到的那样,字符串最多可能有10000
个字符,那么hashValue
肯定会溢出,因为需要将值存储在37^10000
左右。即使这样也会在长度为20
的字符串中失败。
在数论中,
(A+B)%M = (A%M + B%M) % M;
(A*B)%M = (A%M * B%M) % M;
您应该在for循环中应用模运算。但是如果你在最后或执行for循环时进行模运算,两者都会给出相同的答案如果溢出没有发生。
所以相应地做出改变,
public static long hash2 ( String key ){
int hashVal = 0;
for( int i = 0; i < key.length(); i++ )
{
hashVal = (37 * hashVal) + key.charAt(i);
hashVal%=20011;
}
return hashVal;
}
答案 1 :(得分:1)
hashVal
是一个整数。您的哈希函数很可能导致整数溢出。
您可以使用Math.abs()
轻松解决此问题,以确保hashVal
为正数。 e.g。
hashVal = hashVal == Integer.MIN_VALUE ? 0 : Math.abs(hashVal);
return hashVal % 20011;
mod %
是为了确保计算出的最终索引在表格的范围内(例如,如果它&gt; =&gt; = 20011,它就像你说的那样使用除法的余数。 #39;环绕&#39;)。