Java 散列到负值
差不多就是标题:我正在散列一堆名字(10000个左右),其中一些以负数输出。(表大小为20011) 所讨论的哈希函数是:Java 散列到负值,java,hash,Java,Hash,差不多就是标题:我正在散列一堆名字(10000个左右),其中一些以负数输出。(表大小为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; } 公共静态长
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;
}
公共静态长哈希2(字符串键){
int hashVal=0;
对于(int i=0;i
我四处寻找,我想我必须做些与“环绕”有关的事情。但我不知道该怎么做 这是一个明显的
整数溢出
。正如您在问题中提到的,字符串最多可以包含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;
}
公共静态长哈希2(字符串键){
int hashVal=0;
对于(int i=0;i
这是一个明显的整数溢出案例。正如您在问题中提到的,字符串最多可以包含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;
}
公共静态长哈希2(字符串键){
int hashVal=0;
对于(int i=0;i
hashVal
是一个整数。您的哈希函数很可能导致整数溢出
通过使用Math.abs()
确保hashVal
为正数,可以轻松解决此问题。e、 g
hashVal = hashVal == Integer.MIN_VALUE ? 0 : Math.abs(hashVal);
return hashVal % 20011;
mod%
用于确保计算的最终索引在表的范围内(即,如果大于等于20011,则使用除法的剩余部分作为“环绕”)。hashVal
是一个整数。您的哈希函数很可能导致整数溢出
通过使用Math.abs()
确保hashVal
为正数,可以轻松解决此问题。e、 g
hashVal = hashVal == Integer.MIN_VALUE ? 0 : Math.abs(hashVal);
return hashVal % 20011;
mod%
用于确保计算的最终索引在表的范围内(即,如果大于等于20011,则使用除法的剩余部分作为“环绕”)。如果不确定是否为“环绕”,则使用Math.toIntExact
。如果是这样的话,这应该抛出一个异常。另外,考虑到您的方法返回类型是long
为什么不将hashVal
声明为long呢?既然您定义了hash2()
来返回long
,为什么要将int
用于hashVal
?在那里也使用long
。如果您不确定它是否为“环绕”,请使用Math.toIntExact
。如果是这样的话,这应该抛出一个异常。另外,考虑到您的方法返回类型是long
为什么不将hashVal
声明为long呢?既然您定义了hash2()
来返回long
,为什么要将int
用于hashVal
?在那里也使用long
。注意Math.abs(Integer.MIN_值)
返回Integer.MIN_值
。可以修改为Math.abs(hashVal%20011)
,尽管我不确定它如何影响分布。@StefanWarminski更新以反映这种特殊情况。@JaroslawPawlak否,Math.abs(hashVal%20011)=(hashVal%20011)
即使hashVal为负。但是,您可以执行((hashVal%20011)+20011)%20011)
了解更多信息。请注意Math.abs(Integer.MIN_值)
返回Integer.MIN_值
。可以修改为Math.abs(hashVal%20011)
虽然我不确定它是如何影响分发的。@StefanWarminski更新以反映这种特殊情况。@JaroslawPawlak否,Math.abs(hashVal%20011)=(hashVal%20011)
即使hashVal为负值。但是,您可以执行((hashVal%20011)+20011)%20011)
以了解详细信息。