在一个非常大的文件中查找出现次数最多的元素


12

我听说这个面试问题问了很多,我希望就好的答案给出一些意见:您有一个大于10 GB的大文件,并且您想找出哪个元素出现得最多,什么是好的方法去做这个?

在地图上进行迭代并保持跟踪可能不是一个好主意,因为您会占用大量内存,并且在条目进入时保持跟踪并不是最好的选择,因为提出此问题时文件通常已经存在。

我想到的其他想法包括拆分要迭代的文件并由多个线程处理,然后将这些结果组合在一起,但是映射的内存问题仍然存在。


2
文件的元素是什么?他们是琴弦吗?如果将字符用作元素,则映射将不会出现内存问题。如果要素是文字,那么我再次认为这不是问题。如果您拥有所有可能的子字符串,那么您可能会遇到问题...
Nejc 2012年

1
如果条件是“出现的元素占元素总数的一半以上”,则存在线性解决方案。
st0le 2012年

我相信这些元素通常是字符串。但我看不出地图不是问题。在每个元素都是唯一的更坏情况下,难道您不是将内存需求增加了一倍吗?
2012年

1
如果适用博耶-摩尔多数候选算法,则该算法将在线性时间内运行并且就位。
Juho 2012年

Answers:


6

当您有一个非常大的文件且其中包含许多元素时,但最常见的元素非常常见-出现时间小部分-您可以在线性时间中以单词(表示法中的常数非常小,如果不计入哈希等辅助性事物的存储量,则基本上为2。此外,这对于外部存储非常有用,因为文件一次按顺序处理一个元素,并且算法永不“回头”。一种实现方法是通过Misra和Gries的经典算法,请参阅这些讲义。现在,该问题被称为“重击手”问题(频繁的元素是重击手)。O k O >1/kO(k)O()

假设最频繁的元素出现的时间>一小部分的几分之一似乎很强,但这在一定程度上是必要的!即,如果您可以顺序访问文件(并且如果文件很大,则随机访问会太昂贵),则任何算法总是在恒定的遍数中找到最频繁的元素,那么该算法将在元素数量中使用线性空间。因此,如果您不对输入进行任何假设,就无法击败哈希表。最频繁的元素非常频繁的假设可能是解决负面结果的最自然的方法。k>1/kk

这是的草图,即当单个元素出现的时间超过一半时。这种特殊情况被称为多数投票算法,这是由于Boyer和Moore所致。我们将保留一个元素和一个计数。将计数初始化为1并存储文件的第一个元素。然后依次处理文件:k=2

  • 如果文件的当前元素与存储的元素相同,则将计数增加一
  • 如果文件的当前元素与存储的元素不同,则将计数减少一
  • 如果更新后的计数为0,则“踢出”存储的元素并存储文件的当前元素;将计数增加到1
  • 进行到文件的下一个元素

稍加思考,便会说服您,如果存在“多数”元素,即,出现时间超过一半的元素,那么在处理完整个文件后,该元素将成为存储的元素。

对于一般,保留元素和计数,然后将元素初始化为文件的前不同元素,并将计数初始化为每个元素在看到第个元素之前出现的次数。独特的元素。然后,您执行基本上相同的过程:每次遇到元素时,其元素的计数都会增加;如果遇到未存储的元素,则所有元素的计数都会减少;当某个元素的计数为零时,该元素将被踢出,从而有利于文件的当前元素。这是Misra-Gries算法。k - 1 k - 1 k kkk1k1kk

当然,您可以使用哈希表来索引存储的元素。在终止时,保证该算法返回出现时间超过分数的任何元素。从本质上讲,这是对算法进行的最佳选择,该算法使文件中的传递次数恒定并且仅存储字。1 / k O k k11/kO(k)

最后一件事:找到候选“沉重击球手”(即频繁元素)后,您可以再遍历文件以计算每个元素的频率。这样,您可以将元素彼此排名,并验证所有元素是否均以超过时间的比例出现(如果少于这样的元素,则算法返回的某些元素可能为假阳性)。1 / k k 1k1/kk1


您不能使用Boyer-Moore或Misra-Gries-Demaine算法。所陈述的问题有所不同:您不是在寻找多数元素,而是寻找出现次数大于所有元素出现次数的元素。这是一个简单的反例。令n为元素总数,即n = 2k +1。令前k个元素为0,后k个元素为1,最后一个元素为2。Boyer-Moore算法将报告最后一个元素2,作为潜在多数候选者。但是,对于此特定情况下,输出必须是0或1
马西莫卡法罗

O(1)Ω(n)

我刚刚指出,如果您做出错误的假设,您可能会得到错误的结果。更好的方法是,占用较少的内存,即使可能会花费更多的内存,也可能会产生不正确的结果或正确的结果?如果我不得不选择一个可能不正确的结果,那么我会选择一种随机算法而不是博耶·摩尔,因为我不知道这是真的。
马西莫卡法罗

@MassimoCafaro这不是您需要权衡的。正如我指出的那样,对文件的一次传递很容易验证是否满足假设!
Sasho Nikolov 2012年

@MassimoCafaro,这只是微不足道的解决方案!可以使用CM草图以高概率验证该假设,而无需额外通过。
Sasho Nikolov 2012年

3

显而易见的答案当然是保留一个哈希映射,并按照Nejc的建议在文件中移动时存储元素出现的计数器。这是最佳的解决方案(就时间复杂度而言)。

Θ(nlogn).


您能否详细说明霍夫曼编码方法?我之前写过霍夫曼编码器,但是已经有一段时间了,在这种情况下您将如何使用它?
2012年

@Pat没关系,那部分时间太早了,我以某种方式认为压缩输入是有意义的。
耶内(Jernej)

1

如果最常见的元素比下一个常见的元素更普遍,并且与文件大小相比,不同元素的数量少,则可以对两个元素进行随机抽样,并返回样本中最常见的元素。


此外,如果多次出现少量元素,则可以通过采样找到它们,然后仅对这些元素进行精确计数。
最多
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.