14

可能重复:
如何确保 std::random_shuffle 总是产生不同的结果?

我有一个数组,我希望对其进行洗牌,我使用:

answerPositionArray[0] = 100;
answerPositionArray[1] = 400;
answerPositionArray[2] = 800;
std::random_shuffle(answerPositionArray, answerPositionArray + 2);

但是每次我运行我的程序时,都会出现相同的随机播放,400、800、100。有没有办法让随机播放每次都不同?例如。第一次 100、800、400 然后 800、400、100 等。

谢谢

4

2 回答 2

38

std::random_shuffle(b,e)使用实现定义的随机源,因此无法进行便携控制。通常,实现使用std::rand()等使用std::srand()来播种 rng 通常有效。

// not portable, depends on implementation defined source of randomness in random_shuffle
std::srand(some_seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size);

有一个重载std::random_shuffle()将随机数生成器作为第三个参数。您可以使用此表单来定义随机性的来源,以便您可以播种它。

struct RNG {
    int operator() (int n) {
        return std::rand() / (1.0 + RAND_MAX) * n;
    }
};

std::srand(seed);
std::random_shuffle(answerPositionArray, answerPositionArray+size, RNG());

C++11 引入了另一种std::shuffle采用 UniformRandomNumberGenerator 的算法,允许您使用 C++11<random>生成器:

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);

std::shuffle(std::begin(answerPositionArray), std::end(answerPositionArray), eng);

您的评论表明问题在于您没有改组整个数组,您只是改组前两个元素并且没有触及最后一个元素。

这是如何使用幻数的一个很好的演示,如您的代码中所示:

std::random_shuffle(answerPositionArray, answerPositionArray + 2);
                                                               ^
                                                               |
                                                 magic number --

可能容易出错。相反,您应该尝试编写独立于这些值工作的代码。

// trick for getting an array size
template<typename T, int N> int array_size(T (&)[N]) { return N; }

int answerPositionArray[] = {100, 400, 800};

std::random_shuffle(answerPositionArray,
                    answerPositionArray + array_size(answerPositionArray));

或者,一旦您可以使用 C++11,您就可以在数组上使用std::begin和:std::end

std::random_shuffle(std::begin(answerPositionArray), std::end(answerPositionArray));

或者您可以使用上述数组大小技巧在 C++03 中自己实现begin和运行:end

template<typename T, int N> T *begin(T (&a)[N]) { return a; }
template<typename T, int N> T   *end(T (&a)[N]) { return a + N; }

这些方法允许您避免使用幻数来表示数组大小,因此当您编写或修改代码时,您不太可能错误地使用错误的值。

于 2013-01-08T18:46:25.350 回答
25

C++ 随机数并不是真正随机的——它们是从称为种子的初始值生成的。如果你不设置种子,它总是一样的,所以生成的序列不会改变。std::random_shuffle取决于随机数的生成,因此它也会以这种方式运行。

那么如何设置种子呢?采用:

srand(time(0));

在使用随机数调用函数之前。它将以秒为单位将种子设置为当前时间。不要忘记添加适当的头文件。

于 2013-01-08T18:43:43.430 回答