c++中产生不重复的随机数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++中产生不重复的随机数相关的知识,希望对你有一定的参考价值。
如何用c++产生1-10十个不同的随机数
【解题思路】这个题目要解决两个问题:一是产生随机数;二是不能重复。
●第一个问题:产生随机数。在C++中要产生随机数必须用到两个函数:srand()和rand()函数,使用这两个函数必须包含头文件 <stdlib.h>。其中rand()是产生一个伪随机数,比如:int a=rand();函数返回值的取值范围是int类型的取值范围,如果要取得某个范围的随机数,可以通过取余来实现,比如需要小于100的随机数可以这么写:int a=rand()%100;需要100-199之间的随机数可以这么写:int a=100+rand()%100。但在使用这个函数之前,还必须通过srand()函数来指定一个随机种子,如果没有指定随机种子,程序每次运行产生的随机数系列和顺序是相同的。而且srand()指定了随机种子之后,可以多次使用rand()函数来产生随机数,而不必每次使用rand()都指定种子。为了确保程序每次运行时的随机种子都不一样,最好的办法是使用系统时间作为随机种子,比如:srand((int)time(NULL));
●第二个问题:不重复。这个问题系统没有提供现成的函数,只能由编程者使用程序来实现。实现的方法就是把每一个得到的随机数保存起来,然后当有新的随机数产生的时候一个个比较,如果出现重复就重新产生随机数。
像本题要求随机输出1-10十个不同的随机数,就是既要限定范围,又要不能重复,程序段如下:
【程序代码】
#include <iostream> //控制台操作头文件
#include <stdlib.h> //随机函数头文件
int main() //主函数
int A[10],i,j; //整型数组和变量声明
srand((int)time(NULL)); //设置系统时间为随机种子
for(i=0;i<10;i++) //产生10个随机数
A[i]=1+rand()%10; //得到随机数(范围在1-10之间)
for(j=0;j<i;j++) //判断和前面的数是否重复
if(A[i]==A[j]) i--;break; //如果重复,重新产生随机数
printf("10个1-10的随机数):\\n");
for(i=0;i<10;i++) printf("%d",A[i]); //显示10个随机数
system("PAUSE"); //屏幕暂停,以便看到显示结果
return 0; //结束程序
----------------------------------
下面的代码可以很好帮助初学者理解随机数,也发出来供参考
【程序代码】
#include <iostream> //控制台操作头文件
#include <stdlib.h> //随机函数头文件
int main() //主函数
int A[10],B[10],C[10],D[10],i,j; //整型数组和变量声明
printf("第一批十个随机数(程序每次运行都相同):\\n");
for(i=0;i<10;i++) //产生并显示10个随机数
A[i]=rand(); //得到随机数
printf("%d ",A[i]); //显示随机数
printf("\\n\\n"); //换行
/*上面代码第一次产生10个随机数,因为没有设置随机种子,所以程序每次运行得到的数值都相同*/
srand((int)time(NULL)); //设置系统时间为随机种子
printf("第二批十个随机数(每次运行数值都不同):\\n");
for(i=0;i<10;i++) //产生并显示10个随机数
B[i]=rand(); //得到随机数
printf("%d ",B[i]); //显示随机数
printf("\\n\\n"); //换行
/*上面代码第二次产生10个随机数,因为设置系统时间为随机种子,所以程序每次运行得到的数值都会不同,随机种子只需设置一次,下面都不需要再设置*/
printf("第三批十个随机数(10-29,可能重复):\\n");
for(i=0;i<10;i++) //产生并显示10个随机数
C[i]=10+rand()%20; //得到随机数(%是取余运算符)
printf("%d ",C[i]); //显示随机数
printf("\\n\\n"); //换行
/*上面代码第三次产生10个随机数,因为设置了初始值并使用了取余运算符,可以保证产生的随机数在指定范围内,因为没有是否重复的判断,多运行几次,会发现这10个随机数是可能重复的*/
for(i=0;i<10;i++) //产生并显示10个随机数
D[i]=10+rand()%20; //得到随机数
for(j=0;j<i;j++) //判断和前面的数是否重复
if(D[i]==D[j]) i--;break; //如果重复,重新产生随机数
printf("第四批十个随机数(10-29,不会重复):\\n");
for(i=0;i<10;i++) printf("%d",D[i]); //显示10个随机数
printf("\\n\\n"); //换行
/*上面代码第四次产生10个随机数,因为多了判断代码,确保产生的随机数不会重复*/
system("PAUSE"); //屏幕暂停,以便看到显示结果
return 0; //结束程序
【运行结果】
以上程序在DEV C++运行通过。 参考技术A 算法就是,每生成一个数就与原来生成的数比较,如果有相等的就就重新生成一个数,这样就能保证10个数都不相等了。下面这个程序生成数的范围是0到100:
#include <iostream>
#include <stdlib.h>
#include <time.h>
#define MAX 100
using namespace std;
int main()
int arr[10];
int i=0;
bool ret=false;
srand((unsigned)time(NULL));
while(1)
arr[i]=rand()%MAX+1;
for(j=0;j<i;j++)
if(arr[j]==arr[i])
ret=true;
if(!ret)
i++;
ret=false;
if(i==10)
break;
while(--i)
cout<<arr[i]<<" ";
参考技术B #include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main()
vector<int> nums1,2,3,4,5,6,7,8,9,10;
random_shuffle(nums.begin(),nums.end());
copy(nums.begin(),nums.end(),ostream_iterator<int>(cout," "));
cout<<endl;
为1/n的概率
可以通过(rand() << 16) | rand(), 即高16位和低16位分别产生随机数的方法得到更大的随机数
另外先保存再取是个空间时间都特低效的办法, 更好的算法可以自己搜一下"C++产生不重复随机数" 参考技术D 因为windows下rand函数取值只有32767个,你可以试试rand()*rand(),这样可以生成32767*32767范围的数!
数字比较在awk中产生不正确的结果
我最近在网站上找到了一个脚本:
bash, find nearest next value, forward and backward
这是相对陈旧的,需要50个代表评论,我没有。我试图让它工作,并且不太了解awk语法,但我正在尝试。在我正在使用的测试文件中:
-3.793 0.9804E+00 0.3000E+02
-3.560 0.1924E-01 0.3000E+02
-3.327 0.3051E-04 0.3000E+02
-3.093 0.3567E-08 0.3000E+02
-2.860 0.3765E-06 0.3000E+02
-2.627 0.1119E-02 0.3000E+02
-2.394 0.2520E+00 0.3006E+02
这是脚本:
{
if ($fld > tgt) {
del = $fld - tgt
if ( (del < minGtDel) || (++gtHit == 1) ) {
minGtDel = del
minGtVal = $fld
}
}
else if ($fld < tgt) {
del = tgt - $fld
if ( (del < minLtDel) || (++ltHit == 1) ) {
minLtDel = del
minLtVal = $fld
}
}
else {
minEqVal = $fld
}
}
END {
print (minGtVal == "" ? "NaN" : minGtVal)
print (minLtVal == "" ? "NaN" : minLtVal)
}
当这样运行时:
$ awk -v fld=1 -v tgt=-3 -f awk DOSCAR
生产:
-2.860
NaN
即使有一个下限,我也不太确定如何解决它。原帖没有负数,所以他们没有这个问题。任何帮助表示赞赏。
输入文件中有一个空行,触发了经典的awk陷阱。
核心问题是awk比较运算符的奇怪行为,它不需要您指定是否需要数字或字符串比较。 (<意见>这正是为什么自动比较算子是一个坏主意。</ opinion>)
简而言之,awk中有三种标量类型:数字,字符串和“数字字符串”。程序中的文字是数字或字符串,算术运算符的结果总是一个数字,而字符串连接的结果总是一个字符串。但是你所比较的值 - $fld
和tgt
--都是潜在的“数字字符串”,因为它们来自用户输入。
“数字字符串”是来自用户输入的字符串,恰好“看起来像”一个数字。总的来说,“看起来像一个数字”的定义并不令人惊讶,除了一个细节:空字符串不计算。
如果比较两个数字,则比较是数字。如果比较两个字符串,则比较是字典。但是,如果您要比较的一个(或两个)可能是“数字字符串”,那么比较的类型取决于它是否实际上是“数字字符串”。如果它是“数字字符串”,它会变成一个数字;否则,另一个值变成一个字符串。
因此,如果$fld
是一个空字符串,那么将它与tgt
进行比较将是字符串比较而不是数字比较。空字符串是字符串比较的最小可能字符串,因此它会变小。但是,当你计算$fld - tgt
时,$fld
将被强制转换为数字,在这种情况下,空字符串变为0。
所以有两种可能性。最简单的方法是强制将$fld
改为数字;这至少是一致的:
{
val = $fld + 0
if (val > tgt) {
del = val - tgt
if ( (del < minGtDel) || (++gtHit == 1) ) {
minGtDel = del
minGtVal = val
}
}
else if (val < tgt) {
del = tgt - val
if ( (del < minLtDel) || (++ltHit == 1) ) {
minLtDel = del
minLtVal = val
}
}
else {
minEqVal = val
}
}
END {
print (minGtVal == "" ? "NaN" : minGtVal)
print (minLtVal == "" ? "NaN" : minLtVal)
}
另一种方法是消除指示字段不能是数字的行。对数值进行简单且通常可靠的测试是将值与自身进行比较,并将其作为一个数字进行比较:
(val = $fld + 0) == $fld {
if (val > tgt) {
del = val - tgt
if ( (del < minGtDel) || (++gtHit == 1) ) {
minGtDel = del
minGtVal = val
}
}
else if (val < tgt) {
del = tgt - val
if ( (del < minLtDel) || (++ltHit == 1) ) {
minLtDel = del
minLtVal = val
}
}
else {
minEqVal = val
}
}
END {
print (minGtVal == "" ? "NaN" : minGtVal)
print (minLtVal == "" ? "NaN" : minLtVal)
}
以上是关于c++中产生不重复的随机数的主要内容,如果未能解决你的问题,请参考以下文章