蓄水池抽樣演算法隨機演算法的一種,用來從 n 個樣本中隨機選擇 k 個樣本,其中 n 非常大(以至於 n 個樣本不能同時放入記憶體)或者 n 是乙個未知數。其時間複雜度為 o(n),包含下列步驟 (假設有一維陣列 s, 長度未知,需要從中隨機選擇 k 個元素, 陣列下標從 1 開始), 偽**如下:
init : a reservoir with
the size: k
for i= k+1
to n
m=random(1, i);
if( m <= k)
swap the mth value
and ith value
endfor
理解:演算法首先建立乙個長度為 k 的陣列(蓄水池)用來存放結果,初始化為 s 的前 k 個元素。然後從 k+1 個元素開始迭代直到陣列結束,在 s 的第 i 個元素,演算法生成乙個隨機數 j∈[1,i], 如果 j <= k, 那麼蓄水池的第 j 個元素被替換為 s 的第 i 個元素。
演算法的正確性證明:
定理:該演算法保證每個元素以 k / n 的概率被選入蓄水池陣列。
證明:
當i=k+1時,第k+1個元素被選中的概率是kk
+1,而前k個元素被選中的概率=1 - 被第k+1個元素替換的概率 =1−
kk+1
×1k=
kk+1
,說明前面k+1個元素被取到的概率都是相等的且均為kk
+1。
下面採用數學歸納法進行證明。
假設i=n時,前所有的元素都以kn
被選中。
那麼當i=n+1是,第n+1個元素被選中的概率為kn
+1對於前面的n個元素,每個元素被選中的情況分為兩種:1.前面n次已經被選中並且第n+1次時,第n+1個元素沒有被選中;2.前面n此已經被選中,第n+1個元素被選中但是沒有將其替換掉。不難寫出此時的概率為: kn
×(1−
kn+1
)+kn
×(kn
+1×(
1−1k
))=k
n+1
由此可見,第n+1步也滿足假設條件。所以問題得到證明。
1、利用乙個佇列
2、每次從陣列中,隨機找到乙個數;
若該數沒有被選擇過,那麼就將它放入佇列中;如果被選擇過,就重新隨機
毋庸置疑,這個演算法是可以滿足洗牌的要求的。然而呢,讓我們看一下該演算法時間複雜度。每次選擇乙個數,可能存在已經選擇過的情況。所以該演算法的時間複雜度是o(n* n),並且又多用到了乙個佇列,空間複雜度也不是很好
該演算法類似於插入排序
從陣列的最後乙個數(下標為i)開始,進行隨機取餘(除數為i+1,確保下標不過界)將得到的下標對應的元素和最後乙個數交換將最後乙個數不在視為陣列中的元素,繼續迴圈直到只剩下第乙個元素為止。**如下:
//進行洗牌
void shuffe(int* a, int n)
}
證明:假設總共有n個元素(1~n)順序排列,示意圖如下:
。隨機打亂的意思就是每個元素出現在任意位置的概率為1n
。假設其中第k個元素,隨機到0~k中第p的位置上,計算概率。要是k換位置到p位置上,要滿足首先不能被換到k~n的任意位置,其次在k位置上換到p位置上,則概率為:p=
n−1n
×n−2
n−1×
⋯×kk
+1×1
k=1n
要是k位置上的元素被換到k~n的第q位置上的概率,要滿足首先在q~n不被換,同時在q位置上被換,公式和上面的一樣。因此出現在任意位置上的概率是1n
。類似於蓄水池抽樣演算法。
演算法 蓄水池抽樣
例題 有乙個機器按自然數序列的方式吐出球,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個數就是隨機選擇的。證明 這裡即需要證明每個數出現...