问题描述
如何生成位于0到n-1之间的k个不同的随机顺序的随机整数?(来源于《编程珠玑》第2版的第1章中第7页习题4)
方法1
在使用Random类时,每次选择不同的随机因子并在Next中划定范围。这种方法简单容易实现,看上去似乎是可以满足需求的,但我不知道怎么去证明
static void GenRandoInt1(int n , int [] array, int range);
void Main(string[] args){
int n = 1000000;
int[] array = new int[n];
int range = 5000000;
GenRandomInt1(n, array, range);
Console.ReadKey();
}
void GenRandomInt1(int n, int[] array, int range){
Random random;
for (int i = 0; i < n; i++){
random = new Random(DateTime.Now.Millisecond + i);
array[i] = random.Next(0, range);
random = null;
}
}
方法2
使用内置的HashSet容器,在每一次获取范围内随机数时判断容器内是否已经存在有这个随机数,如果存在就重新算一个随机数。
static void GenRandomInt1(int n, int[] array, int range);
static void GenRandomInt2(int n, int range, HashSet<int> hashArray);
void Main(string[] args){
int n = 1000000;
int[] array = new int[n];
int range = 5000000;
HashSet<int> hashArray = new HashSet<int>();
GenRandomInt1(n, array, range);
GenRandomInt2(n, range, hashArray);
Console.ReadKey();
}
void GenRandomInt2(int n, int range, HashSet<int> hashArray){
Random random = new Random();
int i = 0;
for (i = 0; i < n; i++){
int temp;
do {
temp = random.Next(0, range);
} while (hashArray.Contains<int>(temp));
hashArray.Add(temp);
}
}
void GenRandomInt1(int n, int[] array, int range){
Random random;
for (int i = 0; i < n; i++){
random = new Random(DateTime.Now.Millisecond + i);
array[i] = random.Next(0, range);
random = null;
}
}
网上还有一种不用hash的方法,递归判断数组中是否存在已有的随机数,在这里就不多写。
方法3
找一个gcd(n,m)==1的数m,设一个起点x,那么x=(x+m)%n可以将所有的小于n的数遍历,为了产生视觉更加随机的感觉,可以把方程写为x=(x+m*p)%n,p这里是个素数。利用这个公式可以产生等概率而且不重复的k个随机值。
书上答案
for i = [0, n)
x[i] = i
for i = [0,n)
swap(i, randint(i, n-1))
print x[i]
=========================