找到一本大书中最常用的10个单词

时间:2013-07-09 07:02:03

标签: algorithm data-structures hashmap heap hashtable

我知道在论坛上已经多次询问过这个问题,我没有找到任何可以被认为是最合适的解决方案的“TAGGED”答案 - 所以再问:

我们从书中获得了一个非常大的文本,所有这些文本都无法融入记忆中。我们需要在文本中找到前10个最常出现的单词。什么是最佳(时间和空间)方式?

我的想法:

将文件划分为k个大小的块(这样每个块可以存储在内存中)。现在,对每个块执行外部排序。一旦我们在磁盘上有(N / k) - 排序的文件(假设N是书中文本的总大小) - 我不确定我应该如何继续以便我可以从中获取前10个元素k-排序数组。

另外,如果有不同的想法,请建议。

2 个答案:

答案 0 :(得分:2)

这是流式算法领域的典型问题。显然没有办法在某些堕落的情况下起作用;你需要满足一堆元素,这些元素大约(在明确定义的意义上)你的流中的前k个单词。我不知道任何经典的参考文献,但是一个快速的Google将我带到了this。它似乎对进行流式顶级K的各种技术进行了很好的调查。您可以查看其中的参考资料以获取其他想法。

另一个想法(以及一个不在流媒体模型中飞行的想法)只是随机抽取尽可能多的单词以适应内存,排序和单独使用它们,并对文件进行另一次传递计数命中样本中的单词。然后你可以很容易地找到顶部k。

答案 1 :(得分:1)

编辑:此算法存在问题,特别是递归合并列表使其成为多项式运行时算法。但我会把它留在这里作为一个有缺陷算法的例子。


您不能丢弃任何单词中的单词,因为可能只有一个单词在一个块中存在100次,而另一个单词在100个不同的块中存在一次。

但是您仍然可以使用类似于MapReduce算法的方式处理块。您将每个块映射到一个单词列表(包括计数),然后通过递归地将单词列表合并为一个来减少。

在地图步骤中,将每个单词映射到每个块的计数。按字母顺序排序 ,而不是按计数排列并将列表存储到磁盘。现在,您可以线性地成对地合并列表,而不会在内存中保留两个以上的单词:

  1. 设A和B为要合并的列表文件,R为结果文件
  2. 从A中读取一行+字数+,调用单词a
  3. 从B中读取一行+字数+,调用单词b
  4. 按字母顺序比较单词:
    • 如果a = b
      • 总结他们的计数
      • 将单词和新计数写入R
      • 转到2
    • 如果a> b
      • b包括其数量写入R
      • 从B
      • 中读取新行b
      • 转到4
    • 如果a< b
      • a包括其数量写入R
      • 从A
      • 中读取新行a
      • 转到4
  5. 继续执行此成对合并,直到所有文件合并为单个列表。然后,您可以扫描结果列表一次并保留十个最常用的单词。