我试图在牌组中洗牌。我随机创建两个数字并将它们的值分配给彼此100次。但它不是随机创造的。最奇怪的部分就是这个,我把断点放到了行#&c; ++;"观察程序是否每次都选择不同的卡片。当我调试时,如果我太快点击“继续”按钮,它每次都会创建相同的index1和相同的index2(但index1不等于index2)。我以为可能是因为时间问题。 (当我在继续按钮上点击太快或者我根本没有设置断点时,它会因同一时间而创建相同的数字。) 但如果是这样的话,为什么程序会为index1和index2创建不同的值?他们的线之间没有断点。所以时间必须非常小。它创建了不同的索引。我很困惑。如何摆脱?
编辑:解决方案是在main中使用srand一次。
void mix(string *a){
srand(time(NULL));
if (finisher == 100){
return;
}
string b;
int pos1;
pos1 = rand() % 52;
b = a[pos1];
int pos2;
pos2 = rand() % 52;
cout << a[pos1] << " " << a[pos2] << endl; //These lines are only for testing
a[pos1] = a[pos2];
a[pos2] = b;
cout << a[pos1] << " " << a[pos2] << endl; //These lines are only for testing
counter++;
srand(time(NULL));
mix(a);
}
答案 0 :(得分:4)
如果您使用srand
设置特定种子,rand
将生成某个伪随机整数序列。
来自man rand
:
srand()
函数将其参数设置为新序列的种子 由rand()
返回的伪随机整数。 这些序列 可以通过使用相同的种子值调用srand()
来重复。
time(NULL)
每秒只会更改一次,因此您会遇到这样的行为
此外,正如@LightnessRacesinOrbit在某些评论中提到的那样,您应该只在一次时调用srand
。
从C ++ 11开始,您拥有<random>
标头。 Use that instead.
答案 1 :(得分:3)
根据http://en.cppreference.com/w/cpp/numeric/random/srand
备注:强>
一般来说,伪随机数生成器只能在调用rand()和程序启动之前播种一次。每次希望生成一批新的伪随机数时,不应重复播种或重新播种。
标准做法是使用对时间(0)的调用结果作为种子。但是,time()返回time_t值,并且time_t不保证是整数类型。但实际上,每个主要实现都将time_t定义为一个整数类型,这也是POSIX所需要的。
顺便说一下,为什么不使用C ++ 11随机数生成器生成随机整数值i,均匀分布在闭区间[a,b] ,即,根据离散概率函数分布。见http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
提供的示例代码是cppreference页面。
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 51);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
答案 2 :(得分:2)
您可能遇到调用srand的问题。
您的程序在一秒钟内多次运行shuffle_cards函数。
这意味着您在srand(time(NULL));
中为srand提供的时间戳在多次调用中是相同的。
使用相同种子的两个不同初始化将在随后的rand调用中生成相同的连续结果。
因此,rand()调用的两次都将生成与shuffle_cards函数的第一次调用中相同的index1和index2数字。
解决方案是不要调用srand或调用一次,例如程序启动时,或者不经常调用它。
答案 3 :(得分:1)
正如其他人告诉你的那样,部分问题是对srand
的所有调用。只打电话一次。
这不是你问的问题,但代码并不是改组牌组的好方法。首先,shuffle
应该用循环编写而不是自己调用:
void shuffle(string* a) {
for (int i = 0; i < 100; ++i) {
int index1 = std::rand() % 52;
int index2 = std::rand() % 52;
string temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
}
请注意,此代码使用初始化,而不是定义未初始化的变量,然后为其指定值。此外,我重新安排了顺序,以便更清楚地发生了什么。
但这仍然不是洗牌的好方法;它通常会使大部分甲板保持不变。这是一个很好理解的问题。阅读Fisher-Yates shuffle:
void shuffle(string* a) {
for (int i = 0; i < 51; ++i) {
int idx = std::rand() % (52 - i) + i;
string temp = a[idx];
a[idx] = a[i];
a[i] = temp;
}
}
这可以通过使用标准库的swap
函数来改进:
void shuffle(string* a) {
for (int i = 0; i < 51; ++i) {
int idx = std::rand() % (52 - i) + i;
std::swap(a[i], a[idx];
}
}
而且,除非你把它作为一个学习练习,否则你可以摆脱所有代码:
void shuffle(string* a) {
std::random_shuffle(a, a + 52);
}
请注意,我假设string
这里有char
或某些类似char的类型,而不是std::string
,这些代码都不会合理地工作。