檔案中隨機讀取行問題

WalkingInTheWind發表於2013-05-24

1. 有一個檔案,如何在不知道有多少行的情況下讀取該檔案,從中隨機選擇並輸出一行

當我們讀取第 i (i  > 0) 行時,以 1 / i 的概率選擇第 i 行,並替換掉原來選的行。
即總選擇第一行,並以概率 1 / 2 選擇第 2 行,以概率 1 / 3 選擇第 3 行,依次類推。
到檔案結束時,每個行被選中的概率都相等。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX_LINE_LEN 4096
int main()
{
	srand(time(NULL));
	const char *filename = "input.txt";
	FILE * file = fopen(filename, "r");
	char line_buffer[MAX_LINE_LEN];
	char selection[MAX_LINE_LEN];
	int i = 1;
	while(fgets(line_buffer, MAX_LINE_LEN, file))
	{
		if(rand()%i == 0)
			strcpy(selection, line_buffer);
		++i;
	}
	puts(selection);
	fclose(file);
	return 0;
}
簡單推一下。
到 行時,沒問題,跳過。
到第 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 行儲存,以後每次讀入第 i 行,都以 k / i 的概率把剛讀入的一行隨機替換之前儲存的 k 行中的一行。

#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;
}
簡單推一下。
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 行為止,每行被選取的概率仍然都相同。到檔案結尾同樣滿足。



相關文章