1. 程式人生 > >[轉]文件的行數未知,怎樣在概率控制下,選擇輸出每行

[轉]文件的行數未知,怎樣在概率控制下,選擇輸出每行

問題:如何隨機從n個物件中選擇一個物件,這n個物件是按序排列的,但是在此之前你並不知道n的值?
具體些說,在事先並不知道行數的情況下,如何讀一個文字檔案,隨機選擇並輸出一行?
解答:我們總是選擇第一行,並使用二分之一的概率選擇第二行,使用三分之一的概率選擇第三行,以此類推。在該過程結束的時候,每一行具有相同的選中概率(1/n,其中n是檔案的總行數):
i = 0 while more input lineswith probability 1.0/++ichoice = this input line //如果前面做了選擇,並不會break,而是直到最後一個為止。print choice
這裡比較有些疑惑的是第一行:總是選第一行 為什麼概率還是1/n?
概率=1*(1/2)(2/3)

(3/4)……(n-1/n) =1/n
證明:當做第i步選擇(選擇第i行)時,選擇該行的概率為1/i,則不選擇的概率為(i-1)/i對於一篇有n行的文件,現需證明最終選定第i行的概率為1/n。
當最終選擇第i行,前(i-1)步的選擇對最終結果不會產生影響,第i步選擇的概率為1/i,即選擇第i行,第(i+1~n)步中均採取不選擇的動作,即對於任意j(i+1<=j<=n),當前步的概率為(j-1)/j,那麼最終的概率為:(1/i)((i)/(i+1))…*((n-1)/n) = 1/n
以一篇只有6行的文件為例,最終選擇第2行的概率為:1/2*(2/3)(3/4)
(4/5)*(5/6) = 1/6

擴充套件:原問題可簡化為:如何從n個有序物件中等概率地任意抽取1個,簡記為sample(n,1),其中n未知;
若將該問題改為:如何從n個有序物件中等概率地任意抽取m個,簡記為sample(n,m),其中n未知;
分析:若n已知,sample(n,m)是普通的抽樣問題;當n未知時,可否根據上述演算法進行相應的轉化求解?
解決方案:將sample(n,m)問題轉化為m個sample(n*,1)問題,更具體一點是,轉化為sample(n,1);sample(n-1,1);sample(n-2,1)….;sample(n-m+1,1)問題。仍然以一篇6行文件為例,任取其中2行,做法如下:第一遍,以如下概率選中一行:1(1) 2(1/2) 3(1/3) 4(1/4) 5(1/5) 6(1/6)假設選中第2行,接著概率修改如下:3(1) 4(1/2) 5(1/3) 6(1/4) 1(1/5)