這篇文章主要是乙個閒文。如果您正在尋求乙個理想的隨機排列生成演算法,直接閱讀方法3,或是直接使用stl裡提供的random_shuffle()方法
另外請注意,這裡所討論的演算法並不是新的。
什麼是隨機排列?
乙個隨機排列是一組位於隨機位置的物件。
給定乙個物件,1, 2, 3 ... n,隨機排列看起來就是,
p1, p2, p3 ... pn
其中px是從原來的物件集合中選取的隨機值。
隨機排列對於撲克牌洗牌,隨機產生益智遊戲,產生隨機序列,或者生成乙個隨機子集合集(從 n 個物件中隨機選出 k 個物件),非常有用。
隨機排列生成演算法從天真到成熟,我的真實經驗
為了解釋演算法,我會用乙個輔助函式來產生隨機數。
int random(int min, int max);
其結果是乙個大於或等於 min 且小於 max 的乙個隨機數。
也就是說,結果是位於左閉右開區間內。
方法1,天真的方式
在隨機位置交換兩個元素。重複足夠的次數。
偽**:
cpp**
array data(1..n);
for(enough iterations)
這種方法非常直觀,很簡單,它真的有效,前提是有足夠的迭代,比如對10個元素迭代100次。沒錯,它真的可以工作,我用過很多次。
但最大的問題是,迭代次數要遠遠高於物件數(n),因為在兩次中選擇相同位置的兩個元素的概率是相當大的,概率為1 /(n * n)相當的高。
因此,用這種方法,我們要麼得到糟糕的效能(使用非常高的迭代),要麼是比較差的隨機性(低迭代)。
方法2,從籃子裡取小球
假設所有的物件都是球。我們把所有的球到乙個籃子,然後從籃子裡隨機拿出乙個球,如是重複直到籃子變空。
偽**:
cpp**
array data(1..n);
basket = new
array;
for(i = 0 to n - 1)
for(i = 0 to n - 1)
這種方法也很直觀,因為在現實中,彩票**正是用這種方法,而且用的是真正的籃子和球。
而且這種方法效能很好,具有o(n)的時間複雜度。
理論上,其結果是能保證足夠隨機的,因為所有的球是從籃子裡隨機選擇。
方法3,演進 - 在籃球裡原地選擇
第二種方法是很好的實現,而且很容易操作。但是,在計算機世界中,它有乙個缺點:它需要乙個額外的臨時緩衝區來作為籃子。
在大多數情況下這沒什麼,不是個問題,但我們是否可以做得更好呢?
當然可以!我們可以在就在籃子裡選擇。
實際的 c++ **:
cpp**
intrandom(
intminvalue,
intmaxvalue)
else
} template
<
typename
t>
void
randompermutation(t & data,
intcount)
} c 版本的非模板randompermutation(用你需要的資料型別替換 "int" ,並自行實現 swap 函式)
cpp**
void
randompermutation(
int* data,
intcount)
} 上面的**正是籃子方法的實現,不過比較隱晦。
了解原理
讓我們假設籃子是有n個槽的長形籃子。則籃子是線性的。
那麼初始籃子的樣子,
1,2,3,4,5,6,...,n
現在假設我們隨機選擇5,那麼籃子裡的樣子,
1,2,3,4,e,6,...,n
e表示空的槽。
接下來我們不刪除e,我們把 5 之前的所有槽向後移動乙個位置,並把 5 放在第乙個槽裡
5,1,2,3,4,6,...,n
下次如果我們選擇3,我們只是移動 3 之前 5 之後的所有槽,然後把3個在那裡,
5,3,1,2,4,6,...,n
重複n次
很好,是嗎?我們不需要乙個額外的緩衝區。但是,我們必須移動很多槽,不好玩。
如果第 c 次選擇,我們只是把候選的元素與第 c 個元素交換,怎麼樣?
上面的迭代會進行以下變化,
1, 2, 3, 4, 5, 6, ..., n // 初始
5, 2, 3, 4, 1, 6, ..., n // 隨機選擇 5, 和 1 交換
5, 3, 2, 4, 1, 6, ..., n // 隨機選擇 3, 和 2 交換
這正是上面**做的事情。
全排列生成演算法(一)
對於給定的集合a,其中的n個元素互不相同,如何輸出這n個元素的所有排列 全排列 這裡以a為例,來說明全排列的生成方法,對於這個集合,其包含3個元素,所有的排列情況有3 6種,對於每一種排列,其第乙個元素有3種選擇a,b,c,對於第乙個元素為a的排列,其第二個元素有2種選擇b,c 第乙個元素為b的排列...
一種隨機數生成演算法
隨機數生成類 class randnumber randnumber randnumber unsigned long s 0 else unsigned short randnumber random unsigned long n double randnumber frandom unsign...
隨機數生成演算法的研究
摘 要 本文通過流程圖和實際例程,較詳細地闡述了隨機數生成的演算法和具體的程式設計,分析了其符合演算法特徵的特性。1引言 在 資料結構 演算法分析與設計 科學模擬等方面都需要用到隨機數。由於在數學上,整數是離散型的,實數是連續型的,而在某一具體的工程技術應用中,可能還有數 據值的範圍性和是否可重複性...