今天为了想做个排序算法的小实验,自己写了一个生成不重复的随机数组的工具。
关于随机数的生成,网络上最广泛的例子就是利用rand()、srand()和time()三个Linux自带库函数组成的随机数生成模块。其代码如下:
static unsigned int CreateRamdomNum(void)
{
srand(time(NULL));
return rand();
}
我上网查找了许多资料,发现生成数组的办法有很多种。
一种是不断遍历,发现重复就丢弃生成出来的随机数重新生成;还有一种是把生成过的随机数从随机数生成器中剔除;还有更高端的是用离散数学的方法(太高端了我也看不懂,就不说了)...本人才疏学浅,用了最笨的办法,发现重复的就丢掉重来,用于生成数组的代码如下:
unsigned int *CreateRamdomArray(unsigned int num)
{
unsigned int *p_head;
int i,j;
p_head = (unsigned int*)malloc(sizeof(unsigned int)*num);
if(NULL == p_head){
perror("Application of memory failed!\n");
return NULL;
}
memset(p_head,0,sizeof(unsigned int)*num);
for(i=0; i<num; i++){
*(p_head + i) = CreateRamdomNum();
for(j=0; j<i; j++){
if(*(p_head + i) == *(p_head + j)){
*(p_head + i) = CreateRamdomNum();
j = -1;
}
}
}
return p_head;
}
运行之后发现用这种方法生成不重复的随机数组不是一般的低,生成一个20个不重复随机数的数组需要20多秒的时间。刚开始我以为是自己的程序设计有问题,经过一番改良优化之后发现还是“然并卵”,整个程序的运行时间并没缩短多少。
经过几次运行后发现一个规律,用这种方法生成一个10个随机数的数组的时间大约为10秒,生成一个30个随机数数组的时间大约就30秒,生成5个也要等上5秒...本人的老爷机虽说已经上了年纪,但也不至于效率这么低吧?
于是我仔细阅读了下time()的说明,发现其计时的最小精度为秒。而rand函数在同一个srand设定下只会生成相同的伪随机数。也就是说,在1秒之内,不管CPU性能多么高,跑得多欢快,time返回值不变,导致srand设置的种子也是同一个,自然rand也只会生成重复的数!根据本人的数组生成办法,就只能把生成出来的数值丢掉,再来一遍,直到time返回的值有变化为止!难怪生成20个就刚好花了20秒。
于是我又上网查找了一番资料,把生成随机数的模块改成这样子:
static unsigned int CreateRamdomNum(unsigned int input)
{
static struct timeval str_TimeVal;
if(input){
gettimeofday(&str_TimeVal,NULL);
srand(str_TimeVal.tv_usec);
}
else{
srand(time(NULL));
}
return (unsigned int)rand();
}
这里新增了一个Linux的库函数gettimeofday该函数的原型如下:
#include <sys/time.h>
int gettimeofday(struct timeval *tv,struct timezone *tz);
/* 而结构体timeval的定义为 */
struct timeval{
long int tv_sec; // 秒数
long int tv_usec; // 微秒数};
重新编译再跑了一遍,运行时间0.1s!即使是生成30个不重复的随机数数组时间也在1秒之内。QTN的time,以后再也不想用它了...