我们不得不承认这样一个事实:那就是尽管在高级程序语言设计中包含了类似于Random产生随机数之类的方法,但是它产生的随机数并不能满足我们日常所有需要,因为它可能重复——设想一下,电子化抽取试题的原理就是根据预定产生的题目数量产生果敢若干个对应的随机数,然后将匹配的试题抽取、排序并打印在试卷上。但是在同一次考试时候不允许同一题目出现重复(尽管这样的概率很低,但是我们绝对不允许这样做!)。所以避免产生重复随机数的方法(产生“真正的随机数”)成了我们必须研究的话题。今天本文就讨论一下。
方法1:去重法
这是最容易想到的方法,逐个产生这些随机数,每产生一个,都跟前面的随机数比较,如果重复,就重新产生。
这种方法效率比较低,且比较次数呈线性增长,越往后次数越多。
方法2:筛选法
所谓“筛选法”就是根据要产生随机数指定的范围(起始数必须小于终止数),将这些数全部装入一个数组,然后利用系统随机函数(比如 Random )随机产生一个下标,将这个下标对应的数值返回并删除对应的这个数,直到这个数组为空。
(C#)
public sealed class TureRandom
{
private ArrayList nums=new ArrayList();
public TureRandom (int startnum, int endnum)
{
if (startnum >= endnum)
throw new Exception("对不起,起始数字必须小于结尾数字!")
else
for (int i=startnum; i<=endnum;++i)
nums.Add(i);
}
public int GetNum()
{
if (nums.Count <= 0) Then
throw new Exception("对不起,指定范围的随机数全部产生过了。")
else
{
Random r = new Random();
int index=(int)(r.NextDouble()*10+1);
int returnnum =(int)(nums[index]);
nums.RemoveAt(index);
return returnnum;
}
}
}
方法3:
int a[100]={0};
int i, m;
for(i=1; i<=99; ++i)
{
while(a[m=rand()%100]);
a[m] = i;
}
这段代码也是随机产生位置,但它预先把整个数组初始化为0,然后随机产生其中一个位置,如果该元素
值为0,表示这个位置还没有被使用过,就把i赋予它;否则,就重新随机产生另一个位置,直到整个数组
被填满。
方法4:
int a[100];
for(i=0; i<=99; ++i) a[i]=i;
for(i=99; i>=1; --i) swap(a[i], a[rand()%i]);
上面这段代码只需要遍历一次就可以产生这100个不重复的随机数,它是如何做到的呢?首先第二行按顺
序用0到99填满整个数组;第三行,是随机产生从0到m-2个数组下标,把这个下标的元素值跟m-1下标的元
素值交换,一直进行到下标为1的元素。因此它只需要遍历一次就能产生全部的随机数。