1、問題定義可以簡化如下:在不知道檔案總行數的情況下,如何從檔案中隨機的抽取一行,並且每行被抽中的概率相等?
首先想到的是我們做過類似的題目嗎?當然,在知道檔案行數的情況下,我們可以很容易的用c執行庫的rand()函式隨機的獲得乙個行數,從而隨機的取出一行,但是,當前的情況是不知道行數,這樣如何求呢?我們需要乙個概念來幫助我們做出猜想,來使得對每一行取出的概率相等,也即隨機。這個概念即蓄水池抽樣(reservoir sampling)。
有了這個概念,我們便有了這樣乙個解決方案:定義取出的行號為choice,第一次直接以第一行作為取出choice ,而後第二次以二分之一概率決定是否用第二行替換 choice ,第三次以三分之一的概率決定是否以第三行替換 choice ……,以此類推,可用偽**描述如下:
i = 0這種方法的巧妙之處在於成功的構造出了一種方式使得最後可以證明對每一行的取出概率都為1/n(其中n為當前掃瞄到的檔案行數),換句話說對每一行取出的概率均相等,也即完成了隨機的選取。while
more input lines
with probability
1.0/++i
choice = this
input line
print choice
具體操作可參考如下偽**:
element randompick(file):證明如下:int count = 0
; while(count <=file.size)
if(random(
0,count) == 0
) picked =file[count];
++count;
return picked
2、可以對其進行擴充套件,即如何從未知或者很大樣本空間隨機地取k個數?
模擬下即可得到答案,即先把前k個數放入蓄水池,對於第 i>=k+1,我們以 k/i 概率決定是否要把它換入蓄水池,換入時隨機的選取乙個作為替換項,這樣一直做下去,對於任意的樣本空間n,對每個數的選取概率都為k/n。也就是說對每個數選取概率相等。
偽**:
init a reservoir with the size k數學證明:add the first k elements into the reservoir
for i = k+1
to n
m = random(1
,i);
if(m
swap the m_th value and i_th value
end
for
一些等概率選取相關的題目:
1.等概率隨機排列陣列(洗牌演算法)
問題描述:假設有乙個陣列,包含n個元素。現在要重新排列這些元素,要求每個元素被放到任何乙個位置的概率都相等(即1/n),並且直接在陣列上重排(in place),不要生成新的陣列。用 o(n) 時間、o(1) 輔助空間。
思路:先想想如果可以開闢另外一塊長度為n的輔助空間時該怎麼處理,顯然只要對n個元素做n次(不放回的)隨機抽取就可以了。先從n個元素中任選乙個,放入新空間的第乙個位置,然後再從剩下的n-1個元素中任選乙個,放入第二個位置,依此類推。按照同樣的方法,但這次不開闢新的儲存空間。第一次被選中的元素就要放入這個陣列的第乙個位置,但這個位置原來已經有別的(也可能就是這個)元素了,這時候只要把原來的元素跟被選中的元素互換一下就可以了。很容易就避免了輔助空間。
詳情:2.單次遍歷,等概率隨機選取問題
問題描述:假設我們有一堆資料(可能在乙個煉表裡,也可能在檔案裡),數量未知。要求只遍歷一次這些資料,隨機選取其中的乙個元素,任何乙個元素被選到的概率相等。o(n)時間,o(1)輔助空間(n是資料總數,但事先不知道)。
詳情:3.單次遍歷,帶權隨機選取問題
問題描述:有一組數量未知的資料,每個元素有非負權重。要求只遍歷一次,隨機選取其中的乙個元素,任何乙個元素被選到的概率與其權重成正比。
詳情:**
海量資料等概率選取問題
1 問題定義可以簡化如下 在不知道檔案總行數的情況下,如何從檔案中隨機的抽取一行,並且每行被抽中的概率相等?首先想到的是我們做過類似的題目嗎?當然,在知道檔案行數的情況下,我們可以很容易的用c執行庫的rand 函式隨機的獲得乙個行數,從而隨機的取出一行,但是,當前的情況是不知道行數,這樣如何求呢?我...
海量資料等概率選取問題
1 問題定義可以簡化如下 在不知道檔案總行數的情況下,如何從檔案中隨機的抽取一行,並且每行被抽中的概率相等?首先想到的是我們做過類似的題目嗎?當然,在知道檔案行數的情況下,我們可以很容易的用c執行庫的rand 函式隨機的獲得乙個行數,從而隨機的取出一行,但是,當前的情況是不知道行數,這樣如何求呢?我...
海量資料等概率選取問題
1 問題定義可以簡化如下 在不知道檔案總行數的情況下,如何從檔案中隨機的抽取一行,並且每行被抽中的概率相等?首先想到的是我們做過類似的題目嗎?當然,在知道檔案行數的情況下,我們可以很容易的用c執行庫的rand 函式隨機的獲得乙個行數,從而隨機的取出一行,但是,當前的情況是不知道行數,這樣如何求呢?我...