php小編小新將為大家揭秘”均勻分布與天真的洗牌”之間的關系。在計算機科學中,洗牌是一種重要的操作,常用于隨機化數據或集合。而均勻分布是指在一定范圍內的隨機數分布是平均的。那么,洗牌是否能保證均勻分布呢?答案并不簡單,讓我們一起來探討這個問題。
問題內容
我正在對一個 3 int 數組進行 600 萬次洗牌。我在地圖中記錄數組的每個排列。下面是使用 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) } }
登錄后復制
由于我正在進行簡單的洗牌,我的理解是它不應該不產生均勻分布的排列。但這就是我得到的:
[184 -6 10] : 1000074 [184 10 -6] : 1000764 [-6 10 184] : 1000766 [10 184 -6] : 998090 [-6 184 10] : 1000479 [10 -6 184] : 999827
登錄后復制
這表明 6 種可能的排列中的每一種都發生大約 100 萬次。為什么我得到的分布看起來是均勻的?
編輯:將代碼更改為僅種子一次。我現在得到:
[-6 184 10] : 999507 [184 -6 10] : 1000401 [10 -6 184] : 1002163 [10 184 -6] : 999236 [-6 10 184] : 999016 [184 10 -6] : 999677
登錄后復制
編輯2:感謝霍布斯,我意識到我犯了一個愚蠢的錯誤。我應該洗牌 a
,而不是 arr
。我現在得到:
[10 -6 184] : 1111056 [-6 10 184] : 888442 [184 -6 10] : 888576 [10 184 -6] : 1109896 [-6 184 10] : 1113148 [184 10 -6] : 888882
登錄后復制
解決方法
您對 arr
進行了超過 600 萬次洗牌,而沒有在兩次洗牌之間將其恢復到其原始狀態 – 換句話說,您的 600 萬次試驗并不是獨立的。盡管每次洗牌的排列分布不均勻,但將這些排列相互疊加 600 萬次會產生非常接近均勻的分布。