我有一个任务是使用定义在java中实现字符串的哈希码。我写了这段代码。
public int hash(String str) {
int hashValue = 0;
int power;
for (int i = 0; i < str.length(); i++) {
power = (str.length() -1 - i);
hashValue = hashValue + str.charAt(i) * (int) Math.pow(31, power);
}
return hashValue;
}
我发现我的方法中的结果与hashcode()的结果仅与长度小于8的字符串相同。这应该是那样的,还是我的方法不准确?我已经看到,可能是字符串超过8个字符的哈希码已经改变了。
答案 0 :(得分:2)
查看jdk中的hashCode实现:
public static int hashCode(byte[] value) {
int h = 0;
int length = value.length >> 1;
for (int i = 0; i < length; i++) {
h = 31 * h + getChar(value, i);
}
return h;
}
可能会发生,您的方法产生的结果与此方法相同。实际上,没关系。它只是一种散列方法 注意,该散列方法不需要“准确”。这是一种将任意对象(字符串)减少为int的方法。您可以使用任何您想要的方法。
答案 1 :(得分:1)
您对字符串的哈希代码的实现类似于Java的String
类的hashCode
实现,但由于Java缩小double
返回的微妙方式,它并不完全相同Math.pow
到int
。
对于字符串"abcdefg"
,长度为7个字符,您的方法和Java的方法一致 - 它们都返回-1206291356。对于字符串"abcdefgh"
,长度为8个字符,您的方法和Java的方法不一致 - 您的返回值为1858279332,而Java的方法返回1259673732。
首先,我们来介绍它们相似的方式。以下是Java 8's code from Grepcode供参考:
public int More ...hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
每次循环发生时,String
的Java实现都会乘以31
因子。实际上,每个角色都有31
的力量。
您的实施尝试使用Math.pow
, which returns a double
直接确定31
乘以字符值的能力。然后你把它转回int
,因为这就是哈希码的类型。
现在,让我们讨论细微差别。
Java String
hashCode
实现仅增加并添加int
s - 即使发生溢出,它也会int
溢出,在此期间保留低32位信息
对于Math.pow
的实施,JLS, Section 5.1.3涵盖了将double
转换为int
时发生的原始缩小转化。
将浮点数转换为整数类型T需要两个步骤:
- 醇>
在第一步中,浮点数转换为long(如果T为long)或转换为int(如果T为byte,short,char或int),如下所示:
如果浮点数为NaN(§4.2.3),则转换的第一步结果为int或long 0。
否则,如果浮点数不是无穷大,则浮点值将四舍五入为整数值V,使用IEEE 754舍入为零的模式舍入为零(第4.2.3节) 。然后有两种情况:
一个。如果T很长,并且这个整数值可以表示为long,那么第一步的结果就是长值V.
湾否则,如果此整数值可以表示为int,则第一步的结果是int值V.
- 否则,以下两种情况之一必须为真:
一个。该值必须太小(大幅度或负无穷大的负值),第一步的结果是int或long类型的最小可表示值。
湾该值必须太大(大幅度或正无穷大的正值),第一步的结果是类型为int或long 的最大可表示值。
(大胆强调我的)
如果您有一个7个字符的字符串,则计算31 6 ,即887,503,681,仍然可以表示为int
。但是,如果你有一个8个字符的字符串,你计算31 7 ,即27,512,614,111,并且它太大而不适合int
- int的最大值是大约20亿。缩小转换将其转换为最大整数值,即2,147,483,647。此时,您使用的值与Java的String
hashCode方法有效使用的值不同。真正答案的低32位是 not 保留在您的方法中,就像在Java的String
hashCode
方法中一样。这是一个微妙的差异,当你的字符串是8个字符更长时,它会改变你的价值。