試證明 Knuth Shuffle 為均勻的

證明 Knuth Shuffle

Knuth Shuffle 偽碼

Shuffle an array A, length is N (0-based)

  For i = 0 to N-1
      r = Random between i and N  (include i, exclude N)
      exchange A[i], A[r]
 Loop

簡單來說,就是

1. 從第一個位置開始,走訪

2. 從該位置(含)以後的位置中,隨機挑一個。

3. 交換走訪到的位置、與挑中位置內的元素。

4. 進入下一個位置,重複直到歷遍所有位置。

重點在於第二點,請注意隨機挑選的範圍,被挑中的元素就固定在挑中他的位置上了,不會參加之後的挑選。

這個的C#實作,點部落很多篇文章,我就不特別著墨了。

 

當初想出這個洗牌法時,興高采烈地發在部落格上(yahoo部落格、已收)

經前輩點醒,這個算法是有名的Knuth Shuffle。

之後就用得理所當然,卻沒想過這算法是否真的是對的。

今天就來探討一下,這個演算法是否成立。

 

一個洗牌動作,除了打亂,更要亂得均勻。

何謂亂得均勻?

  • 任一張牌,落在任何位置的機率均相等。
  • 任一位置,放置每一張牌的機率均相等。

這兩點其實是同一件事。所以只需要證明其中一點,即可證明演算法成立。

 

證明的方法不只一個,這邊我用數學歸納法來證明。

 

命題:

長度 N 的陣列A,陣列位置為 {L1,L2,L3,…,Ln},初始狀態的內部元素為{E1,E2,E3,…,En}

定義 P(i,j) = 實行Knuth Shuffle後,Ej 位於 Li 的機率。

證明任意 i、j 組合,P(i,j) = 1 / N。

 i=1~nj=1~nP(i,j) =1 / N

 

N = 1 時, A = {1},PN(1, 1) = 1 = 1/N 成立。

 

1. 假設 N = m 時 ,i=1~mj=1~mP(i , j)= 1 / m = Pm成立。

 

N = m+1

 

 

2. 任意位置Li ,放置的Em+1機率為  P(i, m+1), 1 ≤ i ≤ m+1

(到L1~Li-1 均沒有選中Em+1做交換) * (Li 時選中Em+1做交換)   

因為被選中、放到前面的元素,並不在下一次的隨機範圍內,所以若在L1~Li-1 之中就選到Em+1,則Em+1就不可能被Li 選到。

Li 亂數選擇元素時,可隨機選擇的元素會剩下(m+2-i)個,

選中某元素的機率為1/(m-i+2),沒選中的機率為(m-i+1) /(m-i+2)

(到L1~Li-1 均沒有選中Em+1做交換)   =

[m /(m+1)] * [(m-1) /m] * ... * [(m-i+3) /(m-i+4)] * [(m-i+2) /(m-i+3)]

可以觀察得,前項的分子會等於後項的分母,故可簡化,只留第一項的分母與最後一項的分子。

= (m-i+2) / (m+1)

(Li 時選中Em+1做交換) = 1/(m-i+2)

任意位置Li ,放置的Em+1機率

= (到L1~Li-1 均沒有選中Em+1做交換) * (Li 時選中Em+1做交換)

= [(m-i+2) / (m+1)] * [1/(m-i+2)]

= 1 / (m+1)

i=1~m+1P(i, m+1) = 1 / (m + 1)

 

 

3. 位置Li 1 ≤ i ≤ m  放置元素Ej 1 ≤ j≤ m   的機率

= 位置Li 放置的Em+1的機率

= 1 – P(i, m+1)  

又 P(i, m+1)已在2. 證明為 1 / (m+1)

1 – P(i, m+1)  

= 1 – [1 / (m+1)] = m / (m+1)

 

在這個部分事件下,Li 所能放置的元素為{E1,E2,E3,…,Em},

注意到了沒?這時和我們假設母體和N = m 時的狀況一致,Pm = 1 / m

1/m是局部事件的機率,要算出整體機率要乘上母體發生的機率。

所以可以這樣:

位置Li 1 ≤ i ≤ m  放置元素Ej 1 ≤ j≤ m   的機率

= ( 位置Li 放置的Em+1的機率 ) * (排除 Em+1 時, Li 放置元素Ej 的機率 )

= [m / (m+1)] * Pm = [m / (m+1)] * 1 / m

= 1 / (m+1)

i=1~mj=1~mP(i, j) = 1 / (m + 1)

這部分的機率若難以理解,可以這樣想:

我們有一副52張,不含鬼牌的撲克牌,抽到任何數字的機率均是 4/52。

這時我們加入2張鬼牌,我們知道,抽到鬼牌的機率是2/54。

在加入鬼牌的狀況下,抽到任何數字的機率

= (加入鬼牌後,沒抽到鬼牌的機率) * (沒有鬼牌時抽到任何數字的機率)

= (1 - 2/54) * (4/52) = (52/54) * (4/52)

= 4 / 54

4. 位置Lm+1 ,放置元素的Ei機率  P(m+1, j), 1 ≤ j ≤ m

= 元素 Ei 不放於 (L1~Lm ) 的機率

= 1 - ( 元素 Ei 放於 (L1~Lm ) 的機率和)

= 1 –[ ∑k=1~m P(k, j ) ]

由3. 之證明, k=1~mP(k, j) = 1 / (m + 1) , 1 ≤ j ≤ m

故 ∑k=1~m P(k, j ) = m * [1/(m+1)] = m /(m+1)

1 –[ ∑k=1~m P(k, j ) ]

= 1 - m /(m+1)

= 1 / (m + 1)

j=1~mP(m+1, j) = 1 / (m + 1)

 

 

5. 總結

2. i=1~m+1P(i, m+1) = 1 / (m + 1)

3. i=1~mj=1~mP(i, j) = 1 / (m + 1)

4. j=1~mP(m+1, j) = 1 / (m + 1)

以上三點合併

= i=1~m+1j=1~m+1P(i , j)= 1 / (m+1)

故得以以數學歸納法證明命題成立。