給定乙個n個數的序列,設計乙個演算法將其隨機打亂,保證每個數出現在任意乙個位置的概率相同(也就是說在n!個的排列中,每乙個排列出現的概率相同)。
假設輸入為陣列num[length]。
隨機選乙個數,放到num[0]中,再隨機選數,如果該數已經選過,重新選,直到該數未選過時放入num[1]中,以此類推,直到所有的數都選出來,很明顯,這種選法一共有n!中可能,每種可能出現的概率都相同。
但是該做法效率不高,因為選過的數再選將耗費大量時間。
基於以上演算法的缺陷,我們做出改進:選過的數將不再考慮。比如num[0…k]為已選的數,那麼我們的隨機只在k+1到length-1間進行。
void myswap(int &a, int &b)
void shuffle(int num, int length)
}
解釋一下:
index為本次選的牌的存放位置,rand()%(index+1)產生0到index之間的隨機數,而已選的數的下標為index+1到length-1,所以可以保證已選的數不會再重複選到。
一些小細節:
習慣使用–index而不是index–的原因是:index–需要乙個臨時變數來儲存自減前的index值,而–index,直接先自減,之後返回自身,因此效率更高一些。(當然,實際上編譯器可能會做一些優化,使得兩者的區別不大,這僅僅是乙個良好的程式設計習慣)。
使用逆序:rand()%(index+1)比較方便地產生0到index之間的隨機數,如果是正序,則需要寫成:
for (int
index = 0; index
< length; ++index)
運算多一些,而且不夠簡潔。
最後提乙個點:以上**每次運算的結果都會是一樣的,如果想要每次都不一樣,需要新增種子(使用srand((int)time(0));根據時間來選擇種子)。
每天進步一點點,come on!
(●』◡』●)
本人水平有限,如文章內容有錯漏之處,敬請各位讀者指出,謝謝!
洗牌演算法小結
1.for i 1 to n do swap a i a random 1,n 湊合,但不是真正隨機 2.for i 1 to n do swap a i a random i,n 真正的隨機演算法 其中,random a,b 函式用於返回乙個從a到b 包括a和b 的隨機整數。第乙個 概率事件總的發...
隨機洗牌演算法
問題 給定乙個有序序列1 n,要你將其完全打亂,要求每個元素在任何乙個位置出現的概率均為1 n。解決方案 依次遍歷陣列,對第n個元素,以1 n的概率與前n個元素中的某個元素互換位置,最後生成的序列即滿足要求,1 n的概率可通過rand n實現。見如下程式 void swap int p,int q ...
完美洗牌演算法
原文 完美洗牌問題 給定乙個陣列a1,a2,a3,an,b1,b2,b3.bn,把它最終設定為b1,a1,b2,a2,bn,an這樣的。分析 首先,有的問題要求把它換成a1,b1,a2,b2,an,bn。其實也差不多。我們可以 迴圈n次交換a1,b1,a2,b2,把陣列變為b1,b2.bn,a1,a...