如何洗牌一个标准: : 向量?

我正在寻找一个通用的,可重用的方式来洗牌的 std::vector在 C + + 。这是我目前的做法,但我认为它不是很有效,因为它需要一个中间数组,它需要知道项目类型(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);
}
128758 次浏览

从 C + + 11开始,你应该选择:

#include <algorithm>
#include <random>


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

Live example on Coliru

如果您打算每次都生成不同的排列,请确保在对 std::shuffle的多次调用中重用相同的 rng实例!

此外,如果您希望您的程序在每次运行时创建不同的洗牌序列,您可以使用 std::random_device的输出为随机引擎的构造函数播种:

auto rd = std::random_device {};
auto rng = std::default_random_engine { rd() };
std::shuffle(std::begin(cards_), std::end(cards_), rng);

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

#include <algorithm>


std::random_shuffle(cards_.begin(), cards_.end());

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

srand(unsigned(time(NULL)));
std::random_shuffle(cards_.begin(), cards_.end());

根据@FredLarson 的评论:

这个随机 _ shuffle ()版本的随机性来源是 实现定义,所以它可能根本不使用 rand () 不会有任何效果。

那么 YMMV。

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;
}

如果你正在使用 boost,你可以使用这个类(debug_mode被设置为 false,如果你想随机化在执行之间是可预测的,你必须将它设置为 true) :

#include <iostream>
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <algorithm> // std::random_shuffle


using namespace std;
using namespace boost;


class Randomizer {
private:
static const bool debug_mode = false;
random::mt19937 rng_;


// The private constructor so that the user can not directly instantiate
Randomizer() {
if(debug_mode==true){
this->rng_ = random::mt19937();
}else{
this->rng_ = random::mt19937(current_time_nanoseconds());
}
};


int current_time_nanoseconds(){
struct timespec tm;
clock_gettime(CLOCK_REALTIME, &tm);
return tm.tv_nsec;
}


// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
Randomizer(Randomizer const&);     // Don't Implement
void operator=(Randomizer const&); // Don't implement


public:
static Randomizer& get_instance(){
// The only instance of the class is created at the first call get_instance ()
// and will be destroyed only when the program exits
static Randomizer instance;
return instance;
}


template<typename RandomAccessIterator>
void random_shuffle(RandomAccessIterator first, RandomAccessIterator last){
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > random_number_shuffler(rng_, boost::uniform_int<>());
std::random_shuffle(first, last, random_number_shuffler);
}


int rand(unsigned int floor, unsigned int ceil){
random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil);
return (rand_(rng_));
}
};

你可以用下面的代码来测试它:

#include "Randomizer.h"
#include <iostream>
using namespace std;


int main (int argc, char* argv[]) {
vector<int> v;
v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);
v.push_back(6);v.push_back(7);v.push_back(8);v.push_back(9);v.push_back(10);


Randomizer::get_instance().random_shuffle(v.begin(), v.end());
for(unsigned int i=0; i<v.size(); i++){
cout << v[i] << ", ";
}
return 0;
}

更简单的办法是完全避免播种:

#include <algorithm>
#include <random>


// Given some container `container`...
std::shuffle(container.begin(), container.end(), std::random_device());

这将产生一个新的洗牌每次程序运行。由于代码的简单性,我也喜欢这种方法。

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

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

std::random_device rd;
std::shuffle(container.begin(), container.end(), rd);

根据您必须遵循的标准(C + + 11/C + + 14/C + + 17) ,这个“ cpferences”页面提供了非常好的例子: https://en.cppreference.com/w/cpp/algorithm/random_shuffle