如何改组std :: vector?

lau*_*ent 86 c++ shuffle stdvector

我正在寻找一种通用的,可重用的方式来改变std::vectorC++中的一个.这就是我目前的做法,但我认为它不是很有效,因为它需要一个中间数组,它需要知道项目类型(在这个例子中是DeckCard):

srand(time(NULL));

cards_.clear();

while (temp.size() > 0) {
    int idx = rand() % temp.size();
    DeckCard* card = temp[idx];
    cards_.push_back(card);
    temp.erase(temp.begin() + idx);
}
Run Code Online (Sandbox Code Playgroud)

use*_*016 182

对于C++ 98,您可以使用:

#include <algorithm>
#include <random>

auto rng = std::default_random_engine {};
std::shuffle(std::begin(cards_), std::end(cards_), rng);
Run Code Online (Sandbox Code Playgroud)

从C++ 11开始,你应该更喜欢:

#include <algorithm>

std::random_shuffle(cards_.begin(), cards_.end());
Run Code Online (Sandbox Code Playgroud)

Live example on Coliru

如果您打算每次都生成不同的排列,请务必重复使用rng多个调用中的相同实例std::shuffle!

  • +1 - 请注意,每次运行程序时,这可能会产生相同的结果.如果这是一个问题,您可以添加一个自定义随机数生成器(可以从外部源播种)作为`std :: random_shuffle`的附加参数. (16认同)
  • 您还可以插入自定义随机数生成器作为`std :: random_shuffle`的第三个参数. (8认同)
  • @ Gob00st:它会为程序的每个实例生成相同的结果,而不是每次调用`random_shuffle`.此行为是正常的并且是预期的. (4认同)
  • 我认为您应该在答案中添加如何播种。很多人(也就是我)来到这里是因为他们在谷歌上搜索了“c++, shuffle vector”。 (4认同)
  • @TomášZato`#include <algorithm>` (3认同)
  • @ ParkYoung-Bae谢谢,[我刚刚发现](http://www.cplusplus.com/reference/algorithm/random_shuffle/)。当SO答案不包含包含信息时,这真的很不方便,因为它们位于Google搜索结果的顶部。 (3认同)
  • 似乎没有srand(unsigned(time(NULL))),它每次都会产生相同的结果...... (2认同)

Meh*_*ide 9

http://www.cplusplus.com/reference/algorithm/shuffle/

// shuffle algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::shuffle
#include <vector>       // std::vector
#include <random>       // std::default_random_engine
#include <chrono>       // std::chrono::system_clock

int main () 
{
    // obtain a time-based seed:
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::default_random_engine e(seed);

    while(true)
    {
      std::vector<int> foo{1,2,3,4,5};

      std::shuffle(foo.begin(), foo.end(), e);

      std::cout << "shuffled elements:";
      for (int& x: foo) std::cout << ' ' << x;
      std::cout << '\n';
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么奇怪地使用系统时钟作为种子而不是仅仅使用“std::random_device”? (3认同)

小智 8

除了@Cicada所说的,你应该先播种,

srand(unsigned(time(NULL)));
std::random_shuffle(cards_.begin(), cards_.end());
Run Code Online (Sandbox Code Playgroud)

Per @ FredLarson的评论:

此版本的random_shuffle()的随机性源是实现定义的,因此它可能根本不使用rand().那么srand()就没有效果了.

所以YMMV.

  • 实际上,这个版本的`random_shuffle()`的随机性源是实现定义的,所以根本不能使用`rand()`.那么`srand()`就没有效果了.我之前遇到过这种情况. (14认同)
  • 您应该删除这个答案,因为它是错误的 - 更糟糕的是 - 它看起来是正确的,在某些实现中确实是正确的,但并非全部,这使得这个建议非常危险. (6认同)
  • 正如@Fred上面解释的那样`random_shuffle`用于生成随机数是实现定义的.这意味着在你的实现它使用`rand()`(因此srand()工作)但在我的它可以使用完全不同的东西,这意味着在我的实现,即使我每次运行程序时srand我将得到相同结果. (3认同)
  • @Code:就像我们讨论的那样,它不适用于所有实现。您的答案中没有提到您可以提供自己的数字生成这一事实,并且在任何情况下都与本次讨论无关。我觉得我们在兜圈子:S (2认同)

Apo*_*ica 6

它可以更简单,可以完全避免播种:

#include <algorithm>
#include <random>

// Given some container `container`...
std::shuffle(container.begin(), container.end(), std::random_device());
Run Code Online (Sandbox Code Playgroud)

每次程序运行时,这都会产生新的随机播放。由于代码简单,我也喜欢这种方法。

这是可行的,因为我们只需要std::shuffle一个满足UniformRandomBitGenerator要求std::random_device的 。

注意:如果重复洗牌,最好将 存储random_device在局部变量中:

std::random_device rd;
std::shuffle(container.begin(), container.end(), rd);
Run Code Online (Sandbox Code Playgroud)

  • **这是错误的**。`random_device` 被设计为仅被调用*一次*来播种 PRNG,而不是被一遍又一遍地调用(这可能会快速耗尽底层熵并导致其切换到次优生成方案) (5认同)
  • 您所要做的就是阅读答案来找出答案...没有什么可说的,上面还没有非常清楚地解释过。 (3认同)
  • 这可能是一个需要补充的重要警告,但它远没有像你如此戏剧性地指责那样“错误”。 (3认同)
  • 这添加了哪些 8 年前尚未被接受的答案的内容? (2认同)
  • 旧的接受的答案可能更深入。然而,这正是我在谷歌上搜索这样一个简单问题时所期望的单行瞄准答案。+1 (2认同)