【问题标题】:Count unique words in a long long string [closed]计算长字符串中的唯一单词[关闭]
【发布时间】:2016-01-23 01:52:31
【问题描述】:

假设我在内存中有一整本书(或两本书),我想计算其中唯一单词的数量,我该如何计算?我对小字符串的天真方法是:

create a simple hash, place it in array of fixed size, increment array element
All words for which hash array has 1 in it, are unique.

我想要一个更好的方法来处理我真的很长的字符串。我正在用 C 编码。我认为一种方法是使用以块形式工作并组合结果的工作线程。有没有更好的算法?

【问题讨论】:

  • 你能展示你目前所拥有的代码吗?如果您提出具体问题而不是一般性和开放式的问题,您将更有可能得到答案?
  • 多线程只有在您有多个可用处理器并且使算法显着复杂时才会有所帮助。但是,无论您如何分解它,都需要一段代码来检查每个单词。您简单直接的方法似乎很合理,但我不会使用固定大小的数组,因为您可能会用完空间。
  • 很确定这是trie 被发明来解决的问题。

标签: c string algorithm


【解决方案1】:

正如@user3386109 已经提到的,Trie 将是最佳解决方案。基本思想是创建一个字符树。例如:

                             a
                            / \
                           /   \
                          b     c
                         /     / \
                        /     /   \
                       d     a     b

将包含单词“a”、“ab”、“abd”、“ac”、“aca”和“acb”。只需将该方法扩展为将每个单词映射到其对应计数的 Treemap,整个查找就变成线性的,并且可以并行完成以遍历单词:

trie lookup
trienode node = lookup.root

for char c in input:
    if c == ' ':
        //end of word, increment count
        node.count += 1

        //start with root again
        node = lookup.root
    else:
        //go to matching node in the trie
        if !node.hasChild(c)
            node.insertChild(c)

        node = node.childForChar(c)

if node != lookup.root
     //increment count for last word, if the last char wasn't a space
    node.count += 1

现在只需要分析这种方法构造的trie。这可以通过简单地过滤所有计数大于 0 的节点并列出这些节点的路径及其各自的计数来轻松完成。

您可能希望为标点符号、数字等添加过滤。但是如果对子节点的查找设计得当,这种方法可以扫描O(n)中的整个文本,即使子节点的查找表使用HashTree,查找仍然可以在对数时间内执行,导致@987654325 @,n 是输入文本的长度(输入文本中的字符)。

感谢@PaulHankin 进行基准测试。结果基本上是:根据我们可以限制输入字母的程度,TrieHashTable 效果更好(由@PaulHankin 提出),或者表现更差。如果输入限制为小写字母,则 trie 的性能比 HashTable 好 2.6 倍,如果我们允许所有 256 个 ASCII 字符并使用数组作为查找表,则性能下降到 @987654330 性能的 1.3 倍@。使用HashMap 作为子节点的循环表会进一步降低Trie 的性能,使其运行时间是使用HashTable 的算法的两倍。所以毕竟这个算法的速度真的取决于你愿意限制输入字母的大小。

【讨论】:

  • 总是喜欢那些不加理由的反对票......无论如何,我犯了什么错误?
  • @user3386109 抱歉,意思是O(n)O(n * m)n 作为字数和 m 作为平均字长的复杂性将等同于 O(c) c 是输入文本中的字符数。
  • 是的,你是对的。我在考虑字数,以便与其他作用于单词而不是字符的数据结构进行比较。
  • trie 的性能很可能比哈希表差得多,并且使用的内存要多很多倍。虽然在共享前缀时会重复使用节点,但每个节点(和/或哈希表)中需要的许多指针的成本极难克服,并且会导致可怕的内存局部性。
  • @PaulHankin 我对此表示怀疑。假设子查找被正确实现,一个好的散列函数本身已经消耗了比整个查找更多的运行时间。不过,正如我已经说过的,内存效率是可怕的。但是由于 OP 正在谈论两本书或类似的东西,因此 trie 的内存效率不会那么差,并且与将要分析的数据量相比, trie 不会有那么大的分量。并且哈希表本身很可能会遇到很多冲突,从而导致性能下降。
猜你喜欢
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
相关资源
最近更新 更多