如何从文件中返回随机行?面试问题

时间:2010-01-06 21:06:57

标签: c++ c

我正准备接受电话采访。我在互联网上遇到了这些问题。谁能告诉我一些好的答案?

  1. 假设我给你一个文本文件并要求你编写一个程序,该程序将从文件中返回一个随机行(所有行必须具有相同的返回概率)

  2. 与第1部分相同,但这次整个文本文件无法放入主存储器

  3. 与第2部分相同,但现在你有一个流而不是一个文件。

  4. 请帮忙。

    好的...... @每个人,在我问到这个问题之前我真的有一些想法......看到我的同伴们的无情攻击,我发布了我的答案。请随意攻击他们......

    1:计算文件中'\ n'的数量。生成1和数字之间的随机数,并返回数字-1'\ n'之后的行。

    2:将文件逐个部分地存入主存储器,并按照上述步骤进行操作。

    3:我对此并不太了解,并希望得到任何意见。

    很棒的是你们真的给予灵感来推进......

4 个答案:

答案 0 :(得分:22)

  1. 将所有行读入数组,返回1范围内的随机行和行数。

  2. 最简单:计算行数,随机选择行号,再次浏览文件并返回。

  3. 你只需要记住一行。每个新行的概率为1 / N(N为行读取)。

    伪代码:

    i = 1
    chosen_line = ""
    for line in lines:
        if random() < 1/i:    # random returns a uniform random number in [0,1)
            chosen_line = line
        i += 1
    return chosen_line
    
  4. 算法编号3也可以用于1和2。

答案 1 :(得分:9)

您可以在不必读取内存中的所有行的情况下执行此操作,因此可以很好地处理大型文件。伪代码:

linenum := 0
ret := ''
while more lines to read:
    line := readline()
    linenum := linenum + 1
    r := uniform_random(0, linenum)
    if r < 1:
        ret := line

return ret

证明:我们首先注意到我们始终在ret中保存第一行。如果文件有一行,您将选择它,然后就完成了。

对于双行文件,ret将在100%的时间内保存第一行,第二行将在循环的第二次迭代期间的ret保存50%的时间。因此,每条线的概率为0.5。

现在,让我们假设此方法适用于≤N行的文件。为了证明这意味着它适用于N+1,在循环的(N+1)次迭代中,有1/(N+1)概率选择最后一行(random(0, N+1) < 1有这种可能性)。因此,最后一行有1/(N+1)被选中的概率。选择所有其他行的概率仍然相互相等,我们称之为x。然后,N*x + 1/(N+1) == 1,表示x = 1/(N+1)

感应证明已经完成。

编辑:糟糕,在回复之前没有看到第一个答案的第三个方法。不过,如果只是为了证明,我会在这里保留这篇文章,并且如果有任何错误,其他人有机会纠正它。

答案 2 :(得分:1)

Re 1:使用解决方案2

Re 2:您希望使用RandomAccessFile访问扫描整个文件以计算行数并(可能)缓存每行开头的文件指针。 然后你可以随机选择一个(我假设这个问题不是关于如何生成随机数)并回到那个起点,读取该行并返回它。 如果你想要它快,那么请确保你正在缓冲读数(否则raf是慢的)。

Re 3:如果流不适合内存(即你无法缓存整个内容)而你不知道流中有多少行而没有读取整个流(假设你只能阅读它曾经)然后我看不到解决方案。我也在等待答案...

答案 3 :(得分:-1)

#3:将流写入磁盘上的文件并使用解决方案2.当然,这不是最有效的解决方案,但非常简单。