【问题标题】:hashing algorithm for strings字符串的哈希算法
【发布时间】:2011-04-26 15:27:09
【问题描述】:

我遇到了一种情况,我必须计算字符串中每个单词的出现次数。我决定散列是最好的方法(找到遇到的每个单词的散列值,并在散列值索引的位置增加计数 - 假设我使用一个数组)。我可以使用什么哈希算法来确保为每个字符串生成的哈希值是唯一的?

这导致了一个更大的问题。语言库(例如 Java)如何实现像 hashmap 这样的数据结构,在字符串的情况下生成唯一的哈希值?

我想知道这种算法的实现背后所涉及的数学结构。

【问题讨论】:

标签: algorithm hash


【解决方案1】:

我可以使用什么哈希算法来确保为每个字符串生成的哈希值是唯一的?

没有这样的功能。字符串的空间是无限的,但目标空间是有限的(假设您使用的是 32 位整数)。您不能将无限空间单射到有限空间;肯定有碰撞。

语言库(例如 Java)如何实现像 hashmap 这样的数据结构,在字符串的情况下生成唯一的哈希值?

他们没有;上面的字符串没有唯一的散列函数。

我遇到了一种情况,我必须计算字符串中每个单词的出现次数。我认为散列是最好的方法(找到遇到的每个单词的散列值,并在散列值索引的位置增加计数 - 假设我使用数组)。

你的想法是对的。只需使用字典映射strings 到int。例如,在 C# 中,我们将使用 Dictionary<string, int>。大多数现代语言中都存在类似的东西。让语言/框架处理冲突问题以及不适合您的问题,并专注于在该语言/框架内表达您的想法。

【讨论】:

    【解决方案2】:

    您不能拥有保证唯一性的散列算法;这是pigeonhole principle。为什么不用二叉树?

    【讨论】:

    • 但它不可能在 O(1) 中对二叉树执行插入和删除操作,这正是我正在寻找的......
    • @user441575:你有多少个不同的词?您可能会发现对少量单词进行二分搜索比每次都计算哈希要高效得多。
    【解决方案3】:

    Hashed 不能是一个为每个输入提供唯一输出的一对一函数,因为通常函数的 codomain 小于 domain,所以你的要求是不可能的强>。

    当然,如果字符串的长度是有限的,并且所有可能的字符串的集合都低于一个精确的界限,那么你可以拥有所谓的完美哈希函数

    你可以随便找一个碰撞概率低的好散列函数,从here开始,玩得开心!

    旁注:如果我没记错的话,Java Hashtable 不使用开放寻址。每当发现冲突时,该元素就会通过列表放置在同一个已被占用的单元格中。所以这绝对与你的想法相反。实现不会试图保证唯一性,而是选择一个好的碰撞解决策略,最大限度地减少某些方面

    【讨论】:

      【解决方案4】:

      从理论上讲,您不能保证哈希的唯一性 - 除非您的哈希长度始终与原始字符串一样长或更长,这会适得其反。

      有关这方面的全面解释,请参阅 Tom Archer 的“Are Hash Codes Unique?”。

      【讨论】:

        【解决方案5】:

        您不能 100% 确定,根据定义,哈希可能会发生冲突。

        你可以在grepcode 上看到String 在java 中是如何被散列的。基本上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);
        

        【讨论】:

        • @SLaks,很好,我不知道这篇文章。但正如人们所说,它是针对一组 S 值的,并且很难(几乎不可能)将其应用于“单词”。
        • 我明白了.. 有什么标准算法可以做到这一点吗?
        • @user:不,你不明白。
        【解决方案6】:

        在 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 防弹(大部分)。

        【讨论】:

          【解决方案7】:
          【解决方案8】:

          我认为您正在寻找的是Substring Index 或字符串搜索。我错过了什么吗?

          【讨论】:

            猜你喜欢
            • 2015-10-27
            • 2012-07-12
            • 2011-10-03
            • 1970-01-01
            • 2010-09-20
            • 2022-01-25
            • 2013-02-16
            • 2012-01-18
            相关资源
            最近更新 更多