程式設計珠璣筆記 第12章 取樣問題

2021-07-25 05:54:50 字數 1369 閱讀 3487

整理了這一章提到的幾個演算法,其中蓄水池演算法書中沒有寫,這裡放在一起比較一下,出了方法2是c++的**,其它都是python的實現。

問題:

程式的輸入包括兩個整數m和n,其中m

1、以特定概率順序選擇每乙個數

如果要從r個剩餘的整數中選出s個,則以s/r的概率選擇剩餘整數中的第乙個整數,然後遞迴處理剩下的r-1個數。

select_num = m

remaining = n

for i in range(n):

if (randint() % remaining) < select

print i

select_num -= 1

remaining -= 1

這樣在原始陣列[0, 1, 2, ... , n-1]中順序按規則選取,得到的結果直接就是有序的。

但是如果n比較大,例如生成乙個隨機的32位整數序列,則n是最大的32位整數,這個程式就會比較慢。

空間:o(1)

2、每次隨機選取乙個數,作為乙個被選中的數(經過查重)

用乙個treeset記錄被選中的數,每次從整個候選空間中隨機出乙個數,檢視這個數是否已經在treeset中了,如果是則重新選擇,否則放入treeset。

void gensets(int m, int n)

空間:o(m)

這個程式對於n遠大於m的情況,要比方法1塊很多。

3、將包含整數0~n-1的陣列順序打亂,排序後輸出前m個

arr = [i for i in range(n)]

for i in range(n):

swap(arr[i], arr[randint(i,n-1)])

因為每一次swap之後,前i個數就不再變了,所以可以只swap m次,for迴圈只需要range(m)

最後還需要對前m個數字排序,然後輸出

空間:o(n)

4、蓄水池演算法(和3有點類似)

首先構建乙個可放k個元素的蓄水池,將序列的前k個元素放入蓄水池中。

然後從第k+1個元素開始,以k/i的概率來決定該第i個元素是否被替換到池子中。 當遍歷完所有元素之後,就可以得到隨機挑選出的k個元素。

根據本問題的要求,最後再對m個數進行一次排序。

for i in range(k+1, n):

m = randint(1,i)

if m < k:

swap(arr[m], arr[i])

空間:o(m)

5、優化

-當n為100萬而m為n-10時,即要選出絕大部分的數字,那麼可以先選出10個不包含的,然後輸出剩餘的。

-當m為1000而n為2^31時,可能可以先生成1100w個整數,然後排序並對其掃瞄已刪除重複的元素,最後得到1000w個有序元素的樣本。

程式設計珠璣第12章

正文 如何生成0 n 1內的m個隨機整數 1 方法一 比如要從5個數里選出2個數,第乙個數的概率是2 5,第二個數的概率是1 4,然後是0 3 那麼現在已經很清楚了。可以寫 如下 for int i 0 i n i if rand n i m 2 方法二 可以用乙個set,每生成乙個隨機,就去set...

程式設計珠璣 取樣問題

1.問題描述 程式的輸入包含兩個整數m和n,其中m2.解決思路與 實現 程式設計珠璣上給出了四個函式 1 genknuth 演算法依次考慮整數0,1,2,n 1,並通過乙個適當的隨機測試對每個整數進行選擇。通過按序訪問整數,可以保證輸出結果是有序的 c 實現 void genknuth int m,...

程式設計珠璣之取樣問題

要從0 n 1的整數中取出來m m第二種演算法和以前一篇的洗盤演算法比較相似,但是並不是嚴格的每個數字取到的概率為m n,演算法是這樣的,先生成乙個n維的整數陣列,a值為0 n 1,然後生成m個n內的隨機整數rand,然後交換a i 和a rand i 0.m 1 至於是否是滿足m n證明好像有點難...