我遇到了一种情况,我必须计算字符串中每个单词的出现次数。我决定散列是最好的方法(找到遇到的每个单词的哈希值,并在哈希值索引的位置增加计数 - 假设我使用数组)。我可以使用什么哈希算法来确保为每个字符串生成的哈希值是唯一的?
这导致了一个更大的问题。语言库(例如Java)如何实现像hashmap这样的数据结构,以便在字符串的情况下生成唯一的哈希值?
我想知道实施这种算法背后涉及的数学结构。
答案 0 :(得分:7)
我可以使用哪种哈希算法来确保为每个字符串生成的哈希值是唯一的?
没有这样的功能。字符串的空间是无限的,但目标空间是有限的(比如说你使用的是32位整数)。你无法将无限空间映射到有限空间;必须有碰撞。
语言库(例如Java)如何实现像hashmap这样的数据结构,以便在字符串的情况下生成唯一的哈希值?
他们没有;每个字符串都没有唯一的哈希函数。
我遇到了一种情况,我必须计算字符串中每个单词的出现次数。我认为散列是最好的方法(找到遇到的每个单词的哈希值,并在哈希值索引的位置增加计数 - 假设我使用数组)。
你有正确的想法。只需使用将string
映射到int
的字典。例如,在C#中我们将使用Dictionary<string, int>
。大多数现代语言都存在类似的东西。让语言/框架处理碰撞问题以及不适合您的问题,只关注在该语言/框架内表达您的想法。
答案 1 :(得分:3)
您不能拥有保证唯一性的散列算法;这是pigeonhole principle。为什么不使用二叉树?
答案 2 :(得分:2)
Hashed不能是一对一的函数,它为每个输入提供唯一的输出,因为通常函数的codomain小于域,所以你问的是不可能的强>
当然,如果字符串的长度有限并且所有可能字符串的集合都低于精确边界,那么您可以使用所谓的完美散列函数。
您可以只搜索具有低碰撞概率的良好散列函数,只需从here开始并享受乐趣!
旁注:如果我没错,Java Hashtable
不使用开放寻址。每当发现碰撞时,元素将通过列表放置在相同的已占用的单元格中。所以它绝对与你的想法相反。 implmentations并不试图保证唯一性,而是选择一个良好的碰撞解决策略,最大限度地减少某些方面
答案 3 :(得分:1)
您无法100%确定,根据定义,哈希可能会发生冲突。
您可以在grepcode上看到如何在java中对String
进行哈希处理。基本上HashMap
(和其他基于散列的结构)每次都使用hashCode()
方法。
因此,如果要计算特定单词的迭代次数,则应使用Map<String, Integer>
(在java中)并从那里开始计数。
例如:
Map<String, Integer> words = new HashMap<String, Integer>();
String word = "lol";
Integer count = words.get(word);
if(count == null){
count = 0;
}
words.put(word, count + 1);
答案 4 :(得分:1)
从理论上讲,你不能保证哈希的唯一性 - 除非哈希的长度总是与原始字符串一样长或更长,这会产生反作用。
有关此问题的全面解释,请参阅Tom Archer的“Are Hash Codes Unique?”。
答案 5 :(得分:0)
在Java中,String
的hashCode实现如下:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用int算术,其中s [i]是字符串的第i个字符,n是字符串的长度,^表示取幂。 (空字符串的哈希值为零。)
来源:JavaDoc for java.lang.String
您可能需要考虑使用类似的算法来使您的hashCode子弹证明(主要是)。
答案 6 :(得分:0)
源代码价值千言万语......
String.java,查看 hashCode ()方法:http://www.google.com/codesearch/p?hl=zh-TW#ih5hvYJNSIA/src/share/classes/java/lang/String.java&q=String.java%20hashcode&sa=N&cd=1&ct=rc
HashMap.java,查看 put()方法: http://www.google.com/codesearch/p?hl=zh-TW#ih5hvYJNSIA/src/share/classes/java/util/HashMap.java&q=hashMap.java%20%22V%20put%22&sa=N&cd=1&ct=rc
答案 7 :(得分:0)
我认为你要找的是Substring Index或字符串搜索。我错过了什么吗?