简体   繁体   English

有没有更好的方法来改组 C++ 中的向量?

[英]Is there a better way of shuffling a vector in C++?

I was making a BlackJack/21 game as I'm learning C++ to give me some experience in actually working on a project.我正在制作 BlackJack/21 游戏,因为我正在学习 C++,以便在实际工作中获得一些经验。 I'm coming from Java, where there's a nice Collections.shuflfe(...) feature, but I couldn't find a reliable (and random) solution to achieve a similar result with C++.我来自 Java,那里有一个很好的Collections.shuflfe(...)功能,但我找不到可靠的(和随机的)解决方案来实现与 C++ 类似的结果。

I tried the below, and it's working quite well, but I was wondering if there's a much better way to do this, as I feel like I might not need to be using two vectors.我尝试了下面的方法,效果很好,但我想知道是否有更好的方法来做到这一点,因为我觉得我可能不需要使用两个向量。 However, I can't quite figure out what I could do to replace it, if anything at all.但是,我无法弄清楚我可以做些什么来替换它,如果有的话。 Currently, this is efficient enough for my simple card game, but I want to ask if there's anything I could improve on to make this simpler and/or more efficient for future uses?目前,这对于我的简单纸牌游戏来说已经足够有效了,但我想问一下是否有什么我可以改进的地方,以使其更简单和/或更高效以供将来使用?

template <class T> static vector<T> shuffle(vector<T> input) {
    vector<T> values;
    vector<int> indexes;
    for (int i = 0; i < input.size(); i++) {
        indexes.push_back(i);
    }

    //Seed the random number
    srand(static_cast<unsigned int>(time(NULL)));
    while(!indexes.empty()) {
        //Gets a random index from the currently unused indexes for the input.
        int index = rand() % indexes.size();
        int location = indexes.at(index);

        //Adds the value of the input at the randomly generated location to the new values.
        values.push_back(input.at(location));

        //remove chosen index from the list
        indexes.erase(indexes.begin() + index);
    }

    return values;
}

std::shuffle in <algorithm> should be what you're looking for. <algorithm> std::shuffle应该是您想要的。 Here's an example of it in use. 这是一个正在使用的示例。

#include <iostream>
#include <algorithm>
#include <vector>
#include <random>

int main () {
  std::vector<int> myvector {1,2,3,4,5};

  std::random_device rd;
  std::default_random_engine gen(rd);

  std::shuffle (myvector.begin(), myvector.end(), gen);

  for (int& x: myvector) std::cout << ' ' << x;
  std::cout << std::endl;

  return 0;
}

This example is adapted to use vectors from a version found at http://www.cplusplus.com/reference/algorithm/shuffle/ . 本示例适用于使用来自http://www.cplusplus.com/reference/algorithm/shuffle/的版本的矢量。 Checkout the link for more info on std::shuffle 查看链接以获取有关std::shuffle更多信息

As others have pointed out, there's a shuffle function in the standard libraries... but if you're curious, in-place shuffle is fairly easy to implement. 正如其他人指出的那样,标准库中有一个shuffle函数……但是,如果您很好奇,就地实现shuffle相当容易实现。

template<typename T, typename E>
void shuffle(std::vector<T> & items, E & engine)
{
    for (unsigned i = 0; i < items.size() - 1; i++)
    {
        std::uniform_int_distribution<int> dist(i, items.size() - 1);
        int iTarget = dist(engine);
        std::swap(items[i], items[iTarget]);
    }
}

It works like this: 它是这样的:

  • We divide the vector into shuffled and unshuffled portions, with i being the index of the first unshuffled item. 我们将向量分为改组和未改组部分,其中i是第一个未改组项目的索引。
  • We start with i = 0 : the shuffled portion is empty, and the unshuffled portion comprises the whole vector. 我们从i = 0开始: 改组部分为空,未改组部分包括整个向量。
  • While the unshuffled portion isn't empty, we're going to move items out of it and into the shuffled portion. 虽然未改组的部分不为空,但我们将把项目移出并移入已改组的部分。
    • We pick a random index in the unshuffled range (between i and the end of the vector) and designate it as the "target" item. 我们在未改组的范围内 (在i和向量的结尾之间)选择一个随机索引,并将其指定为“目标”项。
    • We take the first unshuffled item ( items[i] ) and swap it with the target. 我们将第一个未改组的项目( items[i] )与目标交换。
    • The target (now at position i ) is considered shuffled . 目标(现在位于位置i )被认为是随机的 We increment i , meaning that the shuffled portion grew and the unshuffled portion shrank. 我们增加i ,这意味着改组部分增长而未改组部分收缩。

Does this shuffle actually produce a uniform distribution? 这种shuffle实际上会产生均匀的分布吗? See for yourself, with a simple test program: 通过一个简单的测试程序亲自了解一下:

int main()
{
    std::random_device rd;
    std::mt19937 engine(rd());

    static const int N_TEST_CASES = 200000;
    static const int N_ITEMS = 10;

    std::vector<std::vector<int> > distributions;
    distributions.resize(N_ITEMS);
    for (int i = 0; i < N_ITEMS; i++)
    {
        distributions[i].resize(N_ITEMS);
        for (int j = 0; j < N_ITEMS; j++)
            distributions[i][j] = 0;
    }

    for (int iTestCase = 0; iTestCase < N_TEST_CASES; iTestCase++)
    {
        std::vector<int> items;
        items.resize(N_ITEMS);
        for (int i = 0; i < N_ITEMS; i++)
            items[i] = i;

        shuffle(items, engine);

        for (int iItem = 0; iItem < N_ITEMS; iItem++)
            for (unsigned iPosition = 0; iPosition < items.size(); iPosition++)
                if (items[iPosition] == iItem)
                    distributions[iItem][iPosition]++;
    }

    for (int iItem = 0; iItem < N_ITEMS; iItem++)
    {
        std::cout << "Item " << iItem << ":\n";
        for (unsigned iPosition = 0; iPosition < distributions[iItem].size(); iPosition++)
            std::cout << "  Position #" << iPosition << ": " << (float)distributions[iItem][iPosition] / (float)N_TEST_CASES << "\n";

        std::cout << "\n";
    }

    return 0;
}

Make vector<T> input a reference ( vector<T> & input ), iterate over input , and for each iteration 使vector<T> input一个引用( vector<T> & input ),遍历input ,并进行每次迭代

  1. Generate a random integer r in the range of the elements. 生成元素范围内的随机整数r ( 0 <= r < input.size() ) (0 <= r < input.size()
  2. Swap ( std::iter_swap ) the current element with the r 'th element ( r 'th iterator := input.begin() + r ). 用第r个元素( r个迭代器:= input.begin() + r )交换( std::iter_swap )当前元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM