使用并发查找文件中的k个最常用词

时间:2018-11-11 10:37:24

标签: algorithm data-structures concurrency heap trie

这是我发现的面试问题。
第一部分是在文件中找到k最常用的单词。这是一个众所周知的问题,可以在here中找到解决方案。当O(nlogk + k)是文件大小时,此解决方案的运行时间为n

第二部分是在文件中找到k个最常用的词,但这一次使用并发性。这意味着,如果我们可以在系统中并行运行m线程-我们如何改善上述解决方案?

这就是我坚持的地方。首先,我想到了将文件拆分为m个部分,并将每个部分发送到不同的线程,以便他可以进行处理。但是问题在于这些线程将必须共享相同的特里,这意味着它们将必须同步。因此,即使使用这些m线程可以在纸上获得更好的运行时,实际上,我也很确定使用同步会使运行时比上述实现中的运行时更糟。

您是否有一个想法,如何使用并发来实现这一点,以改善运行时间?

3 个答案:

答案 0 :(得分:1)

这是一个map-reduce操作。假设我们有一个长度为N和M线程的文件:

  1. 每个线程都被分配了文件的一部分,并计算了该部分中所有单词的出现频率。假设线程可以以有限的竞争成本并行访问该数据:O(N / M)
  2. 每个线程将单词连续地散列到M个存储桶中,并将存储桶的计数发送到相应的线程,以便每个线程接收单词的大致相等部分的计数:O(N / M)
  3. 每个线程将接收到的计数组合起来以生成其所有单词的总数。那就是合并大小为O(N / M ^ 2)的M个结果:O(N / M)
  4. 每个线程计算其前K个计数并将其发送到结果处理线程:O(log K * N / M)
  5. 结果处理线程组合了M个排序的列表,以提取前K个计数。 重要的是要确保该线程可以在不需要其余数据时停止读取输入列表。然后:O((K + M)log M)

因此,使用M个线程,您可以用O((N / M)* log K +(K + M)* log M)完成整个工作。

如果对第5步使用流式并行合并,则可以将其减少为O((N / M)* log K + K + log M),但这只有在具有 lot < / em>线程。

答案 1 :(得分:0)

如何让每个线程独立地在文件共享中找到最常见的k,然后合并结果?

请注意,我对通过并发读取文件可能带来的任何速度提高表示怀疑,这可能是此问题中最慢的操作。

答案 2 :(得分:0)

您可以使用CountMinSketch以紧凑的O(1)形式大致保持计数。这为您提供了沉重的击球手,而没有保留任何文字。假设使用相同的哈希函数,可以将多个草图合并为简单的数组求和。这允许线程并行处理独立的部分。它与哈希表方法类似,不同之处在于您忘记了单词映射。

下一步将是扫描单词词典以确定top k。如果您为每个线程维护一个词典,则可以将其合并而不是重新扫描文件。对于该列表中的每个项目,您都查询其频率O(1),从而可以对它们进行排名以获得最受欢迎。当我们关心频率顺序而不是单词本身时,我们将O(lg k)减小为O(lg f)。在这种情况下,具有相同流行度的单词将链接在列表上。如果使用O(1)SkipList,我们可以用MinHeap中频率最低的单词来评估一个新单词。

然后添加运行时,

  • O(n/T),其中n是文件大小,T是线程数
  • O(T * m),其中m是唯一单词(基数)的数量,而T线程可能会产生所有m个单词以进行哈希联接
  • O(m * lg f),其中f是最高频率,以查找最受欢迎的单词

这将导致O(n/T) + O(T * m) + O(m * lg f),其中n是迄今为止的主要参数,因此实际上它应减少为O(n)