C++ srand()只能调用一次,否则rand()每次返回相同值
面试的时候写一个洗牌算法,结果遇到这个问题坑死我了,幸运的是面试官也不太看得出来问题出在哪(他主攻Java),所以给了我足够时间去调试……
问题描述:
自己创作的洗牌算法:
#include <iostream>
#include <ctime>
using namespace std;
int GetRandomNumber()
{
int RandomNumber;
srand((unsigned)time(0));//time()用系统时间初始化种。为rand()生成不同的随机种子。
RandomNumber = rand() % 100 + 1;//生成1~100随机数
return RandomNumber;
}
void getRand(int* arr)
{
int i, j, temp;
for (i = 0; i < 100; ++i)
{
j = GetRandomNumber();
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return;
}
int main() {
int a[100], i;
for (i = 0; i < 100; ++i)
a[i] = i + 1;
getRand(a);
for (i = 0; i < 100; ++i)
cout << a[i] << ' ';
}
结果实际运行结果却是这样的:
也就是说只交换了第一个数字,这让我百思不得其解。
原因分析:
于是我询问面试官能否用编译器调试(面试时手撕代码),他问我除了编译器还有什么好的方法,我想到了用cout输出每个变量,看看问题发生在哪。当我输出每次产生的随机数 j 的时候,问题就浮出水面。
于是我就怀疑是不是因为每次调用GetRandomNumber都用了srand函数进行初始化种子。然后因为整个程序运行的时间很短,初始化种子用的系统时间单位是秒,意味着种子是相同的,每次都把伪随机序列初始化成相同的序列,因此每次调用rand返回的都是序列的第一个值,因此是相同的值。
当时面试也管不了那么多,只能把srand改成初始化一次,确实就可以正常运行了。
事后参考相关资料得知srand设置随机生成器的状态,得到一大串序列(通常是4,294,967,296),然后调用rand每次从序列中取第一个,取完塞回序列尾端,之后取第二个、第三个就可以做到伪随机的效果。
因此我的问题就在于每次获取随机数都初始化了队列,在不到一秒的运行时间内这些序列都是相同的。而每次rand都取队列第一个数字,所以每次返回的值都相同。
解决方案:
将代码修正成如下所示即可,总之srand初始化调用一次就行了,之后每次用rand就可以输出伪随机数。否则rand就会一直返回相同的值!
#include <iostream>
#include <ctime>
using namespace std;
void getRand(int* arr)
{
int i, j, temp;
srand((unsigned)time(NULL));
for (i = 0; i < 100; ++i)
{
j = rand() % 100;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return;
}
int main()
{
int a[100], i;
for (i = 0; i < 100; ++i)
a[i] = i + 1;
getRand(a);
for (i = 0; i < 100; ++i)
cout << a[i] << ' ';
}
参考资料:https://www.imooc.com/wenda/detail/558945