生成隨機排列
演算法
要生成 [1..n] 的隨機排列,可以使用演算法 A:
[《計算機程式設計藝術 卷2:半數值演算法(第3版)》演算法 3.4.2P(第 110 頁)]
- 生成排列 [1..n],記為 a,其中 a[1] = 1, a[2] = 2, ..., a[n] = n。
- 生成 [1,n] 範圍內的隨機數 k,交換 a[k] 和 a[n]。
- 生成 [1,n-1] 範圍內的隨機數 k,交換 a[k] 和 a[n-1]。
- ...
- 生成 [1,3] 範圍內的隨機數 k,交換 a[k] 和 a[3]。
- 生成 [1,2] 範圍內的隨機數 k,交換 a[k] 和 a[2]。
注意,不能使用演算法 B:
- 生成排列 [1..n],記為 a,其中 a[1] = 1, a[2] = 2, ..., a[n] = n。
- 生成 [1,n-1] 範圍內的隨機數 k,交換 a[k] 和 a[n]。
- 生成 [1,n-2] 範圍內的隨機數 k,交換 a[k] 和 a[n-1]。
- ...
- 生成 [1,2] 範圍內的隨機數 k,交換 a[k] 和 a[3]。
- 生成 [1,1] 範圍內的隨機數 k,交換 a[k] 和 a[2]。
測試程式
根據演算法 A,我們有以下 C# 程式:
using System;
using System.Collections.Generic;
static class RandomPermutation
{
static readonly Random rand = new Random();
static readonly byte[] seq = {1, 2, 3, 4};
static readonly int len = seq.Length;
static readonly int total = 24000000;
static void Swap<T>(ref T a, ref T b) { T t = a; a = b; b = t; }
static int ToValue(byte[] seq)
{
var z = 0;
foreach (var i in seq) z = z * 10 + i;
return z;
}
static int GetRandomPermutation()
{
var a = (byte[])seq.Clone();
for (var n = len; n > 1; n--)
Swap(ref a[rand.Next(n)], ref a[n - 1]);
return ToValue(a);
}
static void Main()
{
var dict = new SortedDictionary<int, int>();
for (var i = 0; i < total; i++) {
var key = GetRandomPermutation();
int count;
dict.TryGetValue(key, out count);
dict[key] = count + 1;
}
foreach (var kvp in dict)
Console.WriteLine("{0}: {1,7}", kvp.Key, kvp.Value);
}
}
這個程式的 GetRandomPermutation() 方法實現了演算法 A,其餘的是測試程式碼。
要注意的是,C# 語言中,陣列的下標是從 0 開始的。而前面描述演算法 A 時,下標是從 1 開始的。
還有,Random.Next(n) 方法返回 [0,n-1] 範圍內的隨機數。
執行結果
這個程式的某次執行的結果是(冒號後面的數是該排列出現的次數):
1234: 999306
1243: 998918
1324: 1002026
1342: 999857
1423: 1001389
1432: 999892
2134: 1001955
2143: 999700
2314: 999546
2341: 999570
2413: 998781
2431: 999752
3124: 1001541
3142: 999276
3214: 1000892
3241: 1000928
3412: 1001220
3421: 998861
4123: 1000518
4132: 1000431
4213: 1000458
4231: 997699
4312: 997567
4321: 999917
如果把上述程式的 GetRandomPermutation() 方法中的 rand.Next(n) 改為 rand.Next(n-1),則該程式實現了演算法 B,某次執行的結果如下所示:
2341: 4001963
2413: 4003021
3142: 3997535
3421: 3998602
4123: 4000183
4312: 3998696
可見,演算法 B 生成的排列的第 k 位決不會出現 k,所以不是隨機的。
相關文章
- 實現一個炫酷的隨機標籤排列效果(顏色隨機,大小隨機,成菱形排列的列表)隨機
- 一對一聊天原始碼,驗證碼生成隨機數字排列組合原始碼隨機
- python生成隨機數、隨機字串Python隨機字串
- [NOIP2022] 比賽 隨機排列 部分分隨機
- Linux Shell 生成隨機數和隨機字串Linux隨機字串
- JavaScript 生成隨機數JavaScript隨機
- Linux 生成隨機密碼Linux隨機密碼
- matlab 生成隨機數序列Matlab隨機
- C++生成隨機數C++隨機
- JS生成隨機密碼JS隨機密碼
- 隨機數生成器隨機
- 生成隨機字串並排序隨機字串排序
- 隨機字串生成與排序隨機字串排序
- java隨機數生成原理Java隨機
- Python如何隨機生成1到100的隨機數?Python隨機
- 幾種生成隨機數方法隨機
- JavaScript生成隨機顏色值JavaScript隨機
- Python中如何生成隨機數?Python隨機
- 使用Math類生成隨機數隨機
- php生成唯一隨機碼PHP隨機
- 更安全的隨機數生成隨機
- PHP生成卡哇伊隨機頭像PHP隨機
- Matlab 隨機生成兩個數值之間的隨機數Matlab隨機
- 生成固定大小的隨機檔案隨機
- Python生成隨機數random模組Python隨機random
- Golang生成區間隨機整數Golang隨機
- 微信小程式生成隨機數微信小程式隨機
- 巧用物件,生成不重複隨機數物件隨機
- matlab生成0,1隨機序列Matlab隨機
- 應用:隨機生成驗證碼隨機
- 怎麼用Python生成隨機數Python隨機
- 偽隨機數是什麼?偽隨機數生成方法有哪些?隨機
- numpy各種生成隨機數的方法隨機
- C# 生成隨機數,呼叫Random方法C#隨機random
- 在指定範圍內生成隨機數隨機
- Solidity陷阱:以太坊的隨機數生成Solid隨機
- 如何生成指定分佈的隨機數隨機
- 生成真隨機數(綜合轉載)隨機
- QT生成固定長度的隨機字串QT隨機字串