这是Strings的哈希函数
public class GoodHashFunctor implements HashFunctor {
@Override
public int hash(String item) {
String binaryRepString = "";
for(int i = 0; i < item.length(); i++){
// Add the String version of the binary version of the integer version of each character in item
binaryRepString += Integer.toBinaryString((int)(item.charAt(i)));
}
long longVersion = Long.parseLong(binaryRepString, 2) % Integer.MAX_VALUE;
return (int) longVersion;
}
}
然而,当我尝试散列大字符串(大约10-15个字符)时,我遇到错误,因为当它试图解析Long时,它会因为数字太大而死亡。
你们认为我应该怎么做?我的教授说我们不能使用Java的hashCode()
我看到一篇类似的帖子,其中最好的答案是这样散列:
int hash=7;
for (int i=0; i < strlen; i++) {
hash = hash*31+charAt(i);
}
但我不会遇到同样的问题吗?我想这可能需要更长的时间才能以这种新方式打破它。我不知道我很困惑......
答案 0 :(得分:0)
为什么在将每个字符转换为long
之前,需要将每个字符转换为字符串(也是二进制形式)?为什么不只是添加long
的{{1}}值?
这是家庭作业,所以我不会发布代码。您还可以查看任何好的算法手册或在网上搜索有关散列的更多信息。
编辑: 我知道你不想只是总结它们,因为anagrams都会有相同的哈希值。但我认为你已经知道如何避免这种情况。请注意,通过连接位,您基本上是在将值移位到某个位置后将值添加到值中。即“10101”+“10001”与1010100000 + 10001 - 21 <&lt; 5 + 17相同。
通过将每个字符移动与其在字符串中的位置成比例的量,添加到散列的值取决于字符的值和位置。此外,通过简单地乘以而不是缩放来观察相同的效果。
需要注意的另一件事是char
只有64位。在开始溢出之前,你只能将很多long
包装进去。因此,大多数实用的散列函数都采用模数值。当然,这意味着对于无限数量的输入字符串,只有有限数量的可能哈希值。碰撞是不可避免的,但为您的班次/乘数和模型选择的值可以最大限度地减少碰撞次数。
答案 1 :(得分:0)
什么是好的哈希函数在很大程度上取决于你的意思。我知道这听起来很陈词滥调但是它是如此真实。要确定哪个哈希函数最适合您的特定问题域,您必须指定:
输入的时间
输入包含的字母(某个字母表中的字母,或者只是遗传序列中的4个字母,如果你想要一个非常好的散列函数,你甚至需要指定每个字母的预期概率)< / p>
您希望区分字符串的方式(您对MAK答案的评论表明您希望哈希值对于相同字符串的排列不同。所以您的+=
不是候选者,但请参阅以下链接用于满足此要求的某些功能)
这3个注意事项的组合允许您选择一个好的哈希函数,但首先必须指定这3个点。
作为附注:很明显,你的+=
成为一个只适用于短字符串。但即使使用不同的哈希函数,也不会为每个可以放入64位长(Java)的字符串获取唯一的哈希值:即使使用完美哈希,也只能区分2 ^ 64个字符串强>功能。通常,如果您有一个映射aKey-&gt; anObject的哈希表,您仍然存储原始密钥(而不仅仅是该存储桶所代表的哈希值),因此您可以将其与请求的密钥字符串进行比较。
根据您的要求,您可能需要查看加密哈希函数主题,以确定那些是否符合您的要求。然而,首先看看非常好的维基百科条目,它列出了一些好的哈希函数,更重要的是它们是好的情况: http://en.wikipedia.org/wiki/Hash_function