【算法】洗牌算法Fisher–Yates shuffle
C#語言一般都是調用隨機函數Random.Next函數,在一個範圍內隨機出一個數字。但是當我們需要將n個數據隨機選擇k個數。怎麼辦呢?
方案一:隨機出一個數,然後從剩下的數裏面接着隨機。
方案二:每次都從n個數據裏面隨機出一個數,遇到重複的,放回去。接着隨機,直到隨機出k個數。
我們的目的是不管用哪個方案,我們都需要保證選出的數要是等概率的。
方案一:取第1個數是1/n,第二個數是1/(n-1)…1
方案二:最壞的情況下我們從100個裏面隨機出99個,越到後面隨機出來的重複率越高。
Fisher–Yates shuffle
Fisher–Yates shuffle算法是高效和等概率的一個洗牌算法。其核心思想是從1到n之間隨機出一個數和最後一個數(n)交換,然後從1到n-1之間隨機出一個數和倒數第二個數(n-1)交換…假設我們有5個數0,1,2,3,4
0,1,2,3,4
1.從[0,4]這5個位置中(包含0和4)隨機出一個數(比如是3)和4號交換。
0,1,2,4,3
第4號位置放3的概率就是1/5
2.從[0,3]這4個位置中(包含0和3)隨機出一個數(比如是0)和3號交換。
4,1,2,0,3
第3號位置放0的概率就是(4/5)*(1/4)=1/5
3.從[0,2]這3個位置中(包含0和2)隨機出一個數(比如是0)和2號交換。
2,1,4,0,3
第2號位置放4的概率就是(4/5)x(3/4)x(1/3)=1/5
4.從[0,1]這2個位置中(包含0和1)隨機出一個數(比如是0)和1號交換。
1,2,4,0,3
第1號位置放2的概率就是(4/5)x(3/4)x(2/3)x(1/2)=1/5
5.從[0,0]這1個位置中(包含0和0)隨機出一個數(比如是0)和0號交換。
1,2,4,0,3
第0號位置放1的概率就是(4/5)x(3/4)x(2/3)x(1/2)=1/5
其實第5步驟就是不用交換了。
那麼我們再回到之前的問題,取出k個數。其實我們將這幾個數字洗完之後,即已經隨機打亂了。所以從裏面按照順序取出k個數即可。
如果本文對你有所幫助,歡迎讚賞~~~
歡迎關注微信公衆號:Unity遊戲開發筆記
QQ羣: