隨機洗牌演算法

2021-06-21 09:24:52 字數 1134 閱讀 7127

問題:給定乙個有序序列1~n,要你將其完全打亂,要求每個元素在任何乙個位置出現的概率均為1/n。

解決方案:依次遍歷陣列,對第n個元素,以1/n的概率與前n個元素中的某個元素互換位置,最後生成的序列即滿足要求,1/n的概率可通過rand() % n實現。見如下程式:

void swap(int* p, int* q)

void shuffle(int *arr, int n)

}使用數學歸納法證明:

l  當n=1時,idx必為0,所以元素arr[0]在任何乙個位置的概率為1/1,命題成立。

l  假設當n=k時,命題成立,即n=k時,原陣列中任何乙個元素在任何乙個位置的概率為1/k。

則當n=k+1時,當演算法執行完k次時,前k個元素在前k個位置的概率均為1/k。

當執行最後一步時,前k個元素中任何乙個元素被替換到第k+1位置的概率為:(1-1/(k+1)) * 1/k = 1/(k+1); 在前面k個位置任何乙個位置的概率為(1-1/(k+1)) * 1/k = 1/(k+1);

故前k個元素在任意位置的的概率都為1/(k+1)

所以,對於前k個元素,它們在k+1的位置上概率為1/(k+1)。

對於第k+1個元素,其在原位置的概率為1/k+1,在前k個位置任何乙個位置的概率為:(1-k/(k+1)) * (1/k)=1/(k+1),所以對於第k+1個元素,其在整個陣列前k+1個位置上的概率也均為1/k+1。

綜上所述,對於任意n,只要按照方案中的方法,即可滿足每個元素在任何乙個位置出現的概率均為1/n。

擴充套件:一道google面試題

給定乙個未知長度的整數流(數目大於1000),如何從中隨機選取1000個隨機數。

解決方法:

l  定義長度為1000的陣列,對於資料流中的前1000個關鍵字,顯然都要放到陣列中。

l  對於資料流中的的第n(n>1000)個關鍵字,則這個關鍵字被隨機選中的概率為 1000/n。故以 1000/n 的概率用這個關鍵字去替換陣列中的乙個。這樣就可以保證所有關鍵字都以 1000/n的概率被選中。對於後面的關鍵字都進行這樣的處理,這樣就可以保證陣列中總是儲存著1000個隨機關鍵字。

注:以1000/n的概率選擇乙個數替換,可通過rand() % n實現,則這個數被替換到前1000個位置中的概率為1000/n。

隨機洗牌演算法

先看看肖舸老師的文章 隨機洗牌演算法複雜度的比較例項 其實我最初想到的也是那3個方法 1判斷生成的隨機數有沒有重複,2.生成一張布林表,3.雙隨機數。下面給出我的演算法 include include include using namespace std void randcard vector,...

隨機演算法入門 洗牌演算法

洗牌演算法是什麼?其實就理解為生成乙個隨機數列的乙個簡單操作而已。怎麼生成?我們先講下一般我們會想到的乙個解法 標記。怎麼標記呢?假設我們的陣列為a,ai 代表陣列a第i個數。乙個布林陣列b 其他型別的陣列也行 然後把a陣列下標作為狀態空間進行隨機生成,接著把生成過的數下標 i 用 bi 1表示為已...

陣列中隨機抽取 演算法 撲克隨機洗牌演算法分析

洗牌演算法實際上就是常見的隨機問題。我們可以抽象理解為 得到乙個m以內的所有自然數的隨機順序陣列。然而怎麼樣操作才是好的洗牌演算法呢?我們通常認為得保證概率相等。即洗牌之後,如果能夠保證每乙個數出現在所有位置上的概率是相等的。隨機抽出一張牌 檢查這種牌是否被抽取過,如果已經被抽取過,則重新抽取,直到...