生成方案1:
产生第i个随机数,逐个检查之前产生过的随机数(a[0]~a[i-1]) 是否有重复,无重复则放进数组a[i],若有则得新产生,直到没有重复为止。缺点是效率太低,在检测 重复性的问题 上耗费太多。时间复杂度为O(n^3)。
#include
#include
#include
#include
#include /*
* a[]: 放置随机数的起始地址
* size:要产生的随机数的个数(数组大小)
* start:要产生的随机数n的范围,大于等于start
* end:要产生的随机数n的范围,小于end
*/
void rand_gen(int a[], int size, int start, int end )
{
int n,i,k ;
int ok = 1;
for( i = 0;
i<=size-1;
i++ )
{
//如果n与a[0]到a[i-1]的任何值有重复,
//就一直产生随机数,直到不重复
while(1)
{
n = rand() % (end-start) + start ;
ok = 1;
//假设不重复//从a[0]到a[i-1],检测是否有重复
for(k=0;
k<= i-1;
k++ )
{
if( a[k] == n )
{
ok = 0;
break;
//检测到重复
}
} if( ok )
{
a[i] = n;
//没有重复,把n放入数组
break ;
}
}//退出do while,继续第i+1个随机数
}
}
生成方案2:
用一个1000 0000个元素的“数组”, 记录每个数字是否产生。 flag[n] == 1表示n已经存在,为0不存在。这种方案适用于范围较小的情形。时间复杂度O(n),空间复杂度算O(n)吧。内存消耗有点大,实测0.2秒左右
/*
* 申请一块动态内存,1千万字节(大概10MB,比较大)
* 每个字节记录一个数的有无,刚好覆盖[0,1000 0000)
* flag[n]==1,表示随机数n已经产生
* flag[n]==0, 表示随机数n还没有产生过
*/
void rand_gen2(int a[], int size, int start, int end )
{
int n,i,k ;
char * flag = NULL;
flag = (char*)malloc(end);
//将来测试时end设为1000 0000
if( NULL == flag )
{
perror("memory for flag failed");
return ;
}
memset(flag, 0, end);
//初始化为全0 //产生size个随机数
for( i = 0;
i
生成方案3:
与方案2原理一样,只不过用二进位来记录,节约了一点内存。时间复杂度O(n),空间复杂度也算O(n),内存占用1.25MB。
/*
* 用二进位来标示一个随机数是否已经产生,
* 一个字节记录8个数,节约了内存
* 例:flag指向一块动态内存,
* 第0个字节第6位(1或0)记录6是否产生
* 第1个字节第6位(1或0)记录14是否产生
*/
void rand_gen3(int a[], int size, int start, int end )
{
int n,i,k ;
char * flag = NULL;
flag = (char*)malloc(end/8+1);
if( NULL == flag )
{
perror("Memory for flag failed");
return ;
}
memset(flag, 0, end/8+1);
for( i = 0;
i<=size-1;
i++ )
{
//一直产生随机数,直到不重复
while(1)
{
n = rand() % (end-start) + start ;
//对于n来说,它的记录在第n/8个字节里的第n%8位
//为0表示没有产生过,1表示已经产生
if( 0 == (flag[n/8] & 1<<(n%8)) )
{
a[i] = n;
//没有重复,把n放入数组
flag[n/8] = flag[n/8] | ( 1<<(n%8) );
//将n对应记录位 置1
break ;
}
}//退出do while,继续第i+1个随机数
} free(flag);
}
排序方案1:
与生成方案2类似申请一块动态内存,对于所有数,使用一大的flag数组, flag[n]==1,表示随机数n存在,flag[n]==0, 表示随机数n不存在。
先将数组过一遍,将每个数是否存在统计到flag中去,
再从flag的前面开始,发现flag[n]为1的就依次把n输出到数组中去。时间复杂度O(n),内存消耗较大
/*
* 申请一块动态内存,1千万字节(大概10MB,比较大)
* 每个字节记录一个数的有无,刚好覆盖[0,1000 0000)
* flag[n]==1,表示n在数组a[]中
* flag[n]==0, 表示n不在数组中
* 记录完成后再从flag的前面往后面检查
* 若flag[n]为1,就将n依次输出到数组中去
*/
void sort( int a[], int size)
{
int i,k ;
char * flag = NULL;
flag = (char*)malloc(10000000);
if( NULL == flag )
{
perror("memory for flag failed");
return ;
}
memset(flag, 0, 10000000);
//全部初始化为0 for(i=0;
i
排序方案2:
排序方案1的改进版,用二进位来记录,减小内存消耗。
/*
* 用二进位来标示一个随机数是否存在,
* 一个字节记录可8个数,节约了内存
* 例:flag指向一块动态内存,
* 第0个字节第6位为1记录6 存在
* 第1个字节第6位为0记录14不存在
*/
void sort2( int a[], int size)
{
int i,k ;
char * flag = NULL;
flag = (char*)malloc(10000000/8+1);
if( NULL == flag )
{
perror("memory for flag failed");
return ;
}
memset(flag, 0, 10000000/8+1);
//全部初始化为0 for(i=0;
i
主函数
int main()
{
// 0->1000 0000
int i,n;
int a[1000000] = {0};
//在栈上申请这么大个数组居然通过了 srand(time(NULL));
rand_gen3(a,1000000, 0, 10000000);
//产生随机数 for( i=0;
i<1000;
i++ )
{
printf("%d ", a[i]);
}
printf("\n");
printf("=======================================\n");
sort2(a, 1000000);
//排序 for( i=0;
i<1000;
i++ )
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
【生成及排序一百万个不重复的随机数,随机数范围|生成及排序一百万个不重复的随机数,随机数范围 [0, 1000 0000)】