文件中随机读取行问题

1. 有一个文件,如何在不知道有多少行的情况下读取该文件,从中随机选择并输出一行

当我们读取第 i (i  > 0) 行时,以 1 / i 的概率选择第 行,并替换掉原来选的行。
即总选择第一行,并以概率 1 / 2 选择第 2 行,以概率 1 / 3 选择第 行,依次类推。
到文件结束时,每个行被选中的概率都相等。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <time.h>
 5 #define MAX_LINE_LEN 4096
 6 int main()
 7 {
 8     srand(time(NULL));
 9     const char *filename = "input.txt";
10     FILE * file = fopen(filename, "r");
11     char line_buffer[MAX_LINE_LEN];
12     char selection[MAX_LINE_LEN];
13     int i = 1;
14     while(fgets(line_buffer, MAX_LINE_LEN, file))
15     {
16         if(rand()%i == 0)
17             strcpy(selection, line_buffer);
18         ++i;
19     }
20     puts(selection);
21     fclose(file);
22     return 0;
23 }
View Code

简单推一下。
到 行时,没问题,跳过。
到第 2 行时,第 2 行被选中的概率是1 / 2,那第 1 行被选中的概率也是 1 / 2 。
到第 3 行时,第 3 行被选中的概率是 1 / 3,第 1 行和第 2 行被选中的概率是 (1 / 2) * (2 / 3),依次递推。
到第 i 行时,第 1 ~ i 行每行被选中的概率都是 1 / i ,到文件最后一行也是这样。

 

2. 有一个文件,如何在不知道有多少行的情况下读取该文件,从中随机选择并输出k行(假设保证k小于文件总行数)

先读入第 1 ~ k 行保存,以后每次读入第 行,都以 k / i 的概率把刚读入的一行随机替换之前保存的 行中的一行。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_LINE_LEN 4096
int main()
{
    int k = 5;

    srand(time(NULL));

    char line_buffer[MAX_LINE_LEN];
    char **selections = (char **)malloc(k*sizeof(char*));
    for(int i = 0; i < k; ++i)
        selections[i] = (char *)malloc(MAX_LINE_LEN*sizeof(char));

    const char *filename = "input.txt";
    FILE * file = fopen(filename, "r");

    // 先读取 1 ~ k 行
    for(int i = 0; i < k; ++i)
        fgets(selections[i], MAX_LINE_LEN, file);

    int i = k+1;
    while(fgets(line_buffer, MAX_LINE_LEN, file))
    {
        if(rand()%i < k) 
        {
            // 随机替换已有的某一行
            int j = rand()%k;
            strcpy(selections[j], line_buffer);
        }
        ++i;
    }
    for(int i = 0; i < k; ++i)
        puts(selections[i]);

    fclose(file);
    for(int i = 0; i < k; ++i)
        free(selections[i]);
    free(selections);

    return 0;
}
View Code

简单推一下。
设 1 ~ i  ( i  >=  k ) 行每行被选中的概率都为 k / i ,当我们读取第 i + 1 行时,以 k / (i+1) 的概率保留该行,并随机替换已保存的某一行(已保存的每行被替换掉的概率是 1 / k )。这样,第 i + 1 行被选取的概率是 k / (i + 1) ,其他行被选取的概率为
(k / i ) * (1 - k / ( i + 1 ) )  + ( k / i) * (k / ( i + 1 )) *  ( 1 - 1 / k )
前面的是第 i + 1 行不被保留时的情况,后面的是第 i+1 行保留并把该行替换掉的情况,最终结果也是 k / ( i + 1 ),所以到第 i + 1 行为止,每行被选取的概率仍然都相同。到文件结尾同样满足。

转自:http://blog.csdn.net/walkinginthewind/article/details/8971516

posted @ 2013-08-09 08:24  simon1024  阅读(227)  评论(0编辑  收藏  举报