关于 std::random_shuffle 洗牌向量的说明

clarification regarding std::random_shuffle to shuffle the vector

我是 C++ 的初学者,想澄清一些事情。我有一个字符串向量,必须随机打乱它。

我想了解

之间有什么区别
std::random_shuffle(vector.begin(), vector.end());
int myrandom(int i) {
    return std::rand() % i;
}


std::random_shuffle(cards_vector.begin(), cards_vector.end(), myrandom);

只要我在 main.c

的开头调用以下函数,两者似乎都能正常工作
srand(time(NULL)); 

我还在网上找到了另一个解决方案,它使用 std::default_random_engine

    auto rng = std::default_random_engine{};
    std::shuffle(cards_vector.begin(), cards_vector.end(), rng);

但是,上面的解决方案总是return相同的洗牌,即使在 main 中调用随机种子也是如此。我不确定这是不是故意的。

如果有人能向我澄清这一点,我将不胜感激。

函数std::random_shuffle有两个重载。简而言之,这意味着您可以使用不同数量的参数调用相同的函数。

  • 版本 std::random_shuffle(vector.begin(), vector.end()); 调用由实现(编译器、操作系统、标准库等)定义的内部随机生成器。但是,它通常在内部使用 std::rand.

来自文档:

The random number generator is implementation-defined, but the function std::rand is often used.

  • 版本 std::random_shuffle(cards_vector.begin(), cards_vector.end(), myrandom); 使用显式随机生成器(您定义;即 myrandom),它在内部调用 std::rand.

函数std::rand (from C) generate a pseudo-random number。这意味着一旦你设置了 seed 它将生成(每次)相同的数字序列。换句话说,序列是确定性的取决于初始值(称为 seed)。

为了设置 std::rand 的种子(初始值),您需要调用接受种子作为参数的函数 std::srand

语句 srand(time(NULL)); 是用 “随机”(实际上不是)种子初始化生成器的一个古老的常用技巧。事实上,函数 time(NULL) returns 每次都应该不同的当前时间被调用。

因此,每次您的程序启动时,您都会为种子设置不同的数字,并且生成器 std::rand 每次都会产生不同的序列。


请注意: std::random_shuffle 是一个旧的 C++ 函数,它已被弃用。您确实应该使用它的替代品,即 std::shuffle.

However, the solution above always return the same shuffle, even when the random seed is called in main. I am not sure whether that is intended or not.

这背后的原理同上。

在该示例中,您使用的是 另一个 (不同于 std::rand)伪随机数生成器,即 std::default_random_engine{}。此生成器默认使用默认种子进行初始化。

如果您想为不同的应用程序生成不同的结果运行,您需要使用种子初始化生成器,每次启动应用程序时该种子都不同。

更正确的代码是:

#include <algorithm>
#include <chrono>
#include <random>

// ...

auto rng = std::default_random_engine{std::chrono::system_clock::now().time_since_epoch().count()};