php小編小新將為大家揭秘”均勻分布與天真的洗牌”之間的關(guān)系。在計算機科學(xué)中,洗牌是一種重要的操作,常用于隨機化數(shù)據(jù)或集合。而均勻分布是指在一定范圍內(nèi)的隨機數(shù)分布是平均的。那么,洗牌是否能保證均勻分布呢?答案并不簡單,讓我們一起來探討這個問題。
問題內(nèi)容
我正在對一個 3 int 數(shù)組進(jìn)行 600 萬次洗牌。我在地圖中記錄數(shù)組的每個排列。下面是使用 go 的代碼。
package main import ( "fmt" "math/rand" "time" ) func randrange(min, max int) int { return rand.intn(max-min+1) + min } func naiveshuffle(arr *[3]int) { for i := 0; i < 3; i++ { e := randrange(0, 2) arr[e], arr[i] = arr[i], arr[e] } } func main() { rand.seed(time.now().unixnano()) m := make(map[[3]int]int, 6) arr := [3]int{-6,10,184} for i := 1; i <= 6000000; i++ { a := arr naiveshuffle(&arr) m[a]++ } for k, v := range m { fmt.println(k, ":", v) } }
登錄后復(fù)制
由于我正在進(jìn)行簡單的洗牌,我的理解是它不應(yīng)該不產(chǎn)生均勻分布的排列。但這就是我得到的:
[184 -6 10] : 1000074 [184 10 -6] : 1000764 [-6 10 184] : 1000766 [10 184 -6] : 998090 [-6 184 10] : 1000479 [10 -6 184] : 999827
登錄后復(fù)制
這表明 6 種可能的排列中的每一種都發(fā)生大約 100 萬次。為什么我得到的分布看起來是均勻的?
編輯:將代碼更改為僅種子一次。我現(xiàn)在得到:
[-6 184 10] : 999507 [184 -6 10] : 1000401 [10 -6 184] : 1002163 [10 184 -6] : 999236 [-6 10 184] : 999016 [184 10 -6] : 999677
登錄后復(fù)制
編輯2:感謝霍布斯,我意識到我犯了一個愚蠢的錯誤。我應(yīng)該洗牌 a
,而不是 arr
。我現(xiàn)在得到:
[10 -6 184] : 1111056 [-6 10 184] : 888442 [184 -6 10] : 888576 [10 184 -6] : 1109896 [-6 184 10] : 1113148 [184 10 -6] : 888882
登錄后復(fù)制
解決方法
您對 arr
進(jìn)行了超過 600 萬次洗牌,而沒有在兩次洗牌之間將其恢復(fù)到其原始狀態(tài) – 換句話說,您的 600 萬次試驗并不是獨立的。盡管每次洗牌的排列分布不均勻,但將這些排列相互疊加 600 萬次會產(chǎn)生非常接近均勻的分布。