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

2021-07-06 03:27:13 字數 1968 閱讀 3529

又是一道跟概率相關的簡單問題。話說我的概率學的太差了,趁這個機會也從頭開始補習一下。

問題描述:假設有乙個陣列,包含n個元素。現在要重新排列這些元素,要求每個元素被放到任何乙個位置的概率都相等(即1/n),並且直接在陣列上重排(in place),不要生成新的陣列。用o(n) 時間、o(1)輔助空間。

演算法是非常簡單了,當然在給出演算法的同時,我們也要證明概率滿足題目要求。

先想想如果可以開闢另外一塊長度為n的輔助空間時該怎麼處理,顯然只要對n個元素做n次(不放回的)隨機抽取就可以了。先從n個元素中任選乙個,放入新空間的第乙個位置,然後再從剩下的n-1個元素中任選乙個,放入第二個位置,依此類推。

按照同樣的方法,但這次不開闢新的儲存空間。第一次被選中的元素就要放入這個陣列的第乙個位置,但這個位置原來已經有別的(也可能就是這個)元素了,這時候只要把原來的元素跟被選中的元素互換一下就可以了。很容易就避免了輔助空間。

用python來寫一段簡單的程式描述這個演算法:

123

4567

from

random

import

random

defshuffle(li

):rand

=random

()forxin

xrange

(len(li

)-1,

0,-1

):# 逆序遍歷liy=

rand

.randint(0

,x)# 從剩餘資料中隨機選取乙個li[

x],li[

y]=li

[y],li[x

]# 將隨機選取的元素與當前位置元素互換

主要的**僅僅三行而已,淺顯易懂。

來計算一下概率。如果某個元素被放入第i(1≤

i≤n

)個位置,就必須是在前i - 1次選取中都沒有選到它,並且第i次選取是恰好選中它。其概率為:pi

=n−1

n×n−

2n−1

×⋯×n

−i+1

n−i+

2×1n

−i+1

=1n

可見任何元素出現在任何位置的概率都是相等的。

實際上python使用者一定知道,在random類中就有現成的shuffle方法,處理方法與我上面的程式是一樣的。順便也貼在這裡學習一下。以下**來自於 python 2.5 lib\random.py:

250

251252

253254

255256

257258

259260

261262

def

shuffle

(self,x

,random

=none

,int

=int

):"""x, random=random.random -> shuffle list x in place; return none.

optional arg random is a 0-argument function returning a random

float in [0.0, 1.0); by default, the standard random.random.

"""if

random

isnone

:random

=self

.random

fori

inreversed

(xrange(1

,len(x

))):

# pick an element in x[:i+1] with which to exchange x[i]j=

int(

random()*

(i+1

))x[i

],x[j

]=x[

j],x[

i]

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

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

非等概率隨機演算法

自己做了乙個非等概率的隨機演算法的封裝,然後後面人的可以借用。probability是概率,最好是兩位小數,然後返回1的概率是probability,返回0的概率是1 probability 如果是三元組或者是多元組,多返回幾個值就可以了 int notequalprobability float ...

隨機洗牌演算法

問題 給定乙個有序序列1 n,要你將其完全打亂,要求每個元素在任何乙個位置出現的概率均為1 n。解決方案 依次遍歷陣列,對第n個元素,以1 n的概率與前n個元素中的某個元素互換位置,最後生成的序列即滿足要求,1 n的概率可通過rand n實現。見如下程式 void swap int p,int q ...