从文本文件中选择K个随机行

时间:2011-12-01 02:12:56

标签: c++ algorithm random-sample

这是从X行文本中选择随机行的原始问题的扩展,其中所选文本行的概率为1 / X.诀窍是如果查询范围为[0,1)的随机变量Y,则选择第J行,并返回小于1 / J的值。

现在在这个问题的新版本中,我们必须选择K小于X的K个随机行。我相信每行的概率应该是K / X.

我坚持如何将原始解决方案扩展到K线。可能吗?任何解释都会很棒。

2 个答案:

答案 0 :(得分:8)

这可以使用原始算法的推广来解决。直觉如下:保持文件中k个候选行的列表,这些候选行最初被播种到前k行。然后,从那一点开始,在看到文件的第n行时:

  • 选择1到n之间的随机值x,包括在内。
  • 如果x> k,忽略这个元素。
  • 否则,将元素x替换为文件的第n行。

证明这是以k / n概率正确地对每个元素进行采样,其中n是文件中的总行数,如下所示。假设n≥k。我们通过归纳证明每个元素具有被挑选的概率k / n,通过显示在看到z元素之后,这些元素中的每一个都具有被选择的概率k / z。特别是,这意味着在看到n个元素后,每个元素都有所需的概率k / n。

作为我们的归纳基础,如果我们确切地看到k个元素,那么每个元素都被选中。因此,根据需要,被选择的概率是k / k。

对于归纳步​​骤,假设对于某些z≥k,已经以概率k / z选择了每个第一z元素并考虑了(z + 1)st元素。我们选择[1,z + 1]范围内的随机自然数。以概率k /(z + 1),我们决定选择这个元素,然后逐出一些旧元素。这意味着以概率k /(z + 1)选择新元素。对于每个z原始元素,此时选择它的概率是我们在检查第一个z元素之后选择它的概率(概率k / z,通过我们的归纳假设),以及我们的概率保留它是z /(z + 1),因为我们用概率1 /(z + 1)代替它。因此,选择它的新概率是(k / z)(z /(z + 1))= k /(z + 1)。因此,以概率k /(z + 1)选择所有第一z + 1个元素,完成归纳。

此外,该算法在O(n)时间运行并且仅使用O(k)空间,这意味着运行时独立于k的值。要看到这一点,请注意每次迭代都会执行O(1)工作,并且总共有O(n)个交互。

如果您很好奇,我将此算法的实现作为C ++ STL样式算法 available here on my personal site

希望这有帮助!

答案 1 :(得分:-2)

首先使用第一种算法从X行中随机选择第一个元素。然后从剩余的X-1行中选择第二行。运行此过程K次。

任何一组K线的概率为(X choose K)。我将由您来验证此算法是否提供了所需的均匀分布。