蓄水池抽樣演算法是一種抽樣演算法,對於乙個不知道大小的的集合(通常是流式資料),抽取的樣本值能夠保證隨機。
特點:其時間複雜度並不是很高o(n),空間複雜度通常是o(k),能夠很大程度地節省記憶體。
問題:我現在有乙個很長並且不知道多長的序列,怎麼從中取出k個完全隨機的數。
用乙個足夠大的陣列存放所有資料然後隨機這種方法肯定是行不通的,因為我們不知道序列有多長,並且計算機並不能給我們開乙個所謂「足夠大」的陣列。那麼蓄水池抽樣演算法是怎麼做的?
首先,我們要維護乙個大小為k的陣列,存放的就是我們要抽取的那k個數字。先把資料的前k個放到陣列中,然後之後的每乙個資料我們都需要做乙個操作,假設我們現在遍歷完第n個數字(現在的n剛好等於k),我們從取乙個隨機數對n+1取模,如果結果小於k就替換掉陣列中相應位置的元素,如果大於等於k的話就放棄這個數。**如下:
int num, ind = 0;
int arr[k];
while (cin >> num)
int rd = rand() % ind; //這個時候ind就是之前說的n+1
if (rd < k) arr[rd] = num;
ind++;
}
**其實很簡單,但是現在的問題是,為什麼這麼做可以保證我們取到所有資料的概率都是相等的,接下來我們證明一下。
首先,當我們處理完第n個數時,目前任意乙個數字能夠存在於陣列中的概率都是k/n。當我們處理第n+1個數字時,因為我們要取乙個隨機數對n+1取模,如果結果小於k就替換掉陣列中相應位置的元素,如果大於等於k的話就放棄這個數。所以這個數字在執行完這次操作後能留在陣列中的概率為k/n+1,所以,現在我們只需要證明在n-1之前所有數字執行完這次操作後留在陣列的概率也是這個,就可以證明每乙個數字被抽出的概率都相等。
現在來推理一下這個概率,不難理解,它一定等於這個數字本來就在陣列並且第n+1個數沒進陣列的概率加上這個數字在陣列並且第n+1個數進到陣列中但是沒有替換掉它的概率。可能有點長,但是式子是這樣:
k n∗
n+1−
kn+1
+kn∗
kn+1
∗k−1
k\frac * \frac + \frac * \frac * \frac
nk∗n+
1n+1
−k+
nk∗
n+1k
∗kk
−1最後化簡一下就是:
k n+
1\frac
n+1k
剛好和之前計算的第n+1個數字被抽到的概率一樣,所以我們就證明了這種做法是可以做到對每乙個資料的抽取概率相等的。
應用場景:
蓄水池抽樣的應用場景通常來說只是流式資料這種不知道具體有多少的資料。切記並不是「大量的資料」就都用這種方式,這種方式只是非常適用於流式資料。
演算法 蓄水池抽樣
例題 有乙個機器按自然數序列的方式吐出球,1號球,2號球.現有乙個袋子,袋子裡最多只能裝下k個球,並且除袋子以外沒有更多的空間,球扔掉不能放回。設計一種選擇方式,使得當機器吐出第n號球時,袋子中的球數是k個,同時可以保證從1號球到n號球中的每乙個被選中進袋子的概率都是k n。具體例子 有乙個只能裝下...
蓄水池抽樣演算法
給你乙個長度為n的鍊錶。n很大,但你不知道n有多大。你的任務是從這n個元素中隨機取出k個元素。你只能遍歷這個鍊錶一次。你的演算法必須保證取出的元素恰好有k個,且它們是完全隨機的 出現概率均等 蓄水池抽樣演算法 該演算法是針對從乙個序列中隨機抽取不重複的k個數,保證每個數被抽取到的概率為k n這個問題...
蓄水池抽樣演算法
題目 要求從n個元素中隨機的抽取k個元素,其中n無法確定 解法 首先選擇n中的前k個數加入 蓄水池 中,然後從第k 1個數開始,以k k i i 1,2,3.的概率選擇這個數,然後在蓄水池中隨機選擇乙個數,並將其替換,n個元素遍歷完畢後,蓄水池中的k個數就是隨機選擇的。證明 這裡即需要證明每個數出現...