在C ++中,有没有更好的方法来对向量进行改组?

时间:2019-02-15 19:41:12

标签: c++

在学习C ++时,我正在制作一个BlackJack / 21游戏,目的是给我一些实际从事项目的经验。我来自Java,那里有一个不错的Collections.shuflfe(...)功能,但是我找不到可靠的(随机的)解决方案来用C ++达到类似的结果。

我尝试了下面的方法,并且效果很好,但是我想知道是否有更好的方法可以做到这一点,因为我觉得我可能不需要使用两个向量。但是,我根本不知道该怎么做来替换它,如果有的话。目前,这对于我的简单纸牌游戏已经足够有效了,但是我想问一下是否有什么我需要改进的地方,以使其更简单和/或更有效,以备将来使用?

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

3 个答案:

答案 0 :(得分:4)

std::shuffle中的

<algorithm>应该是您想要的。这是一个正在使用的示例。

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

此示例适用于使用http://www.cplusplus.com/reference/algorithm/shuffle/中的版本的矢量。检出链接以获取有关std::shuffle

的更多信息

答案 1 :(得分:2)

正如其他人指出的那样,标准库中有一个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]);
    }
}

它是这样的:

  • 我们将向量分为改组未改组部分,其中i是第一个未改组项目的索引。
  • 我们从i = 0开始:改组部分为空,而未改组部分构成整个向量。
  • 虽然未改组部分不为空,但我们将项目移出并移至改组部分。
    • 我们在未改组的范围内选择一个随机索引(介于i和向量的结尾之间),并将其指定为“目标”项。
    • 我们获取第一个未改组的商品(items[i])并与目标交换。
    • 目标(现在位于i位置)被视为改组。我们增加i,这意味着改组部分增加了,而未改组部分缩小了。

这个shuffle实际上产生均匀分布吗?通过简单的测试程序亲自查看:

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

答案 2 :(得分:0)

vector<T> input作参考(vector<T> & input),在input上进行迭代,并针对每次迭代

  1. 在元素范围内生成随机整数r。 (0 <= {r <input.size()
  2. 用第std::iter_swap个元素(第r个迭代器:= r)交换(input.begin() + r)当前元素。