隨機抽數的概率誤區與洗牌演算法

2022-07-09 14:21:14 字數 979 閱讀 2175

在重新做《複雜》一書中第九章提到的遺傳演算法例子的時候遇到了乙個問題,遺傳演算法驅動的機械人羅比需要在不斷的進化過程中產生出可以清理10x10方格內隨機位置垃圾的最優策略。

10x10方格內的垃圾是隨機放置的,假設需要隨機放置50個垃圾的話,並視10x10網格為長度為100的線性空間,這就需要偽隨機數函式參與從0 ~ 99共100個數字中選出50個不重複的數字作為標號。

最開始沒經過思考,我是這樣做的:

原理就是反覆從0 ~99之中隨機抽取,如果抽到已經抽中的數字的話會重新抽,說實話,這樣的思路很醜,因為會存在一直抽重複數字的情況,但是實際上幾乎不會如此,而且效率並不低。

後來和別人討論改寫了方法

這種方法的思路是建立乙個內容為自身下標的陣列,之後依次把每乙個元素與全域性範圍內隨機選取的元素交換,這樣就產生了乙個隨機的亂序陣列,假設上文之中長度為100的陣列經過亂序之後,取前50個元素的值就可以作為垃圾隨機放置的位置。

但是這種做法是錯誤的,因為概率不等。

最初我簡化了問題規模,改為10選5,這是程式統計出來的0 ~ 9被選中為前5的次數分布。

做了一千萬次運算,可以看出5被選中的概率是最大,9被選中的概率是最小,而且波動是百萬量級的,肯定有問題。

之後聽取別人建議用了洗牌演算法。

只是略加改動,思路是依次選取陣列之中每乙個元素與尾部未亂序序列中隨機抽取的元素交換。同樣是做一千萬次運算,結果得出了大致正確的分布。

再一次把問題規模簡化,簡化成為3選1,這次是做一百萬次運算。

其實最初我也考慮到了概率不等,但是我想了一下元素為兩個的情況,也就是2選1,對於這種情況,如果使用此方法的話概率是相等的,於是想當然的擴充套件到了任意長度上,事實證明這是錯誤的。

當長度縮短到為3的時候,就可以很輕易的畫出樹狀圖。

對於3選1來說,0被選中的概率是9/27,1被選中的概率是10/27,2被選中的概率是8/27。讓人大跌眼鏡啊,這種想當然的方法產生的果然是概率不等的結果。

然後有沒有一句話可以一針見血的說出這種現象產生的運作原因呢?

等概率隨機取數演算法的幾種實現 洗牌演算法)

最近讀了專案中的工具指令碼,發現乙個隨機取數的函式,功能大概是從m個數中不重複的隨機取出n個數,算是陣列隨機排序然後取前n個值的變種。指令碼實現採取原始的方法,每隨機取乙個數就放到乙個陣列中,下次取數時遍歷結果陣列判斷是否已經取出,平均時間複雜度為o mlogm 空間複雜度o n 效率不高。想了一下...

等概率隨機排列陣列(洗牌演算法)

又是一道跟概率相關的簡單問題。話說我的概率學的太差了,趁這個機會也從頭開始補習一下。問題描述 假設有乙個陣列,包含n個元素。現在要重新排列這些元素,要求每個元素被放到任何乙個位置的概率都相等 即1 n 並且直接在陣列上重排 in place 不要生成新的陣列。用o n 時間 o 1 輔助空間。演算法...

概率 隨機數演算法

int generate01 int func else if num1 0 num2 1 return ret int generaterandomnum int max int bit num 0,i 0 int result 0 while 0x01 bit num max bit num w...