第一种方法
如何产生不重复的随机数?最容易想到的方法,是逐个产生这些随机数,每产生一个,都跟前面的随机
数比较,如果重复,就重新产生。这是个很笨的方法,且比较次数呈线性增长,越往后次数越多。其实这些
比较是多余的,完全可以不进行比较,只要反过来,按顺序产生这些数,但随机产生它们的位置。例如下
面产生100个100以内不重复随机数的代码:
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的元素。因此它只需要遍历一次就能产生全部的随机数。
再看下面的代码,原理跟上面例子相似,但效率比上面的差点,但仍不失为一个好方法:
int a[100]={0};
int i, m;
for(i=1; i<=99; ++i)
{
while(a[m=rand()%100]);
a[m] = i;
}
这段代码也是随机产生位置,但它预先把整个数组初始化为0,然后随机产生其中一个位置,如果该元素
值为0,表示这个位置还没有被使用过,就把i赋予它;否则,就重新随机产生另一个位置,直到整个数组
被填满。这个方法,越到后面,遇到已使用过的元素的可能性越高,重复次数就越多,这是不及第一个方
法的地方,但总的来说,效率还是不错的。
这种方法的缺点 是不能产生大于M的随机数(M<=N)
第二种方法
一、动态生成一个数组,其长度是要产生随机数的上界,每个元素的值为其对应的下标。
二、随机生成该范围内的一个数,以该数为数组下标,取出对应的数组中的元素(其实数组中的元素和该随机数一样),取出后,将下标对应的数组元素赋值为-1(赋值-1是因为随机数中或许有0),来作为下次判断的依据。
三、再产生该范围内的随机数,如果对应的数组下标中的元素是-1,就再生成,直到不是-1为止。
四、重复步骤二、三,直到产生够所需的随机数个数。
注意点:随机数个数应小于等于随机数的范围
具体的代码如下:
- void RandomNumbers(int limit,int sum)
- {
- fstream file("data.txt",ios::out);
- int count=0,number=0;
- int *temp=new int[limit];
- for(int i=0;i<limit;i++)
- {
- temp[i]=i;
- }
- srand(static_cast<unsigned int>(time(NULL)));
- for(int i=1;i<=sum;i++)
- {
- number=rand()%limit;
- while(temp[number]==-1)
- {
- number=rand()%limit;
- }
- file<<temp[number]<<"\t";
- count++;
- if(count%10==0)
- {
- file<<endl;
- }
- temp[number]=-1;
- }
- delete []temp;
- temp=NULL;
- file.close();
- cout<<"已产生"<<sum<<"个"<<"大于等于0少于"<<limit<<"的互不相等的随机数"<<endl;
- }
该函数实现的是产生0~limit(包括0和limit)内的sum个随机数。