用于随机选择std :: vector的所有元素的有效方法,无需重新洗牌

时间:2011-12-19 19:26:56

标签: c++ random vector std

我正在寻找一种有效的方法,以随机顺序选择对std::vector<T>的每个元素的访问,而不需要重新调整或复制它们,即不使用std::random_shuffle并确保仅选择每个元素一旦。

我不想复制或重新调整为a)T的每个实例都可能是一个非常大的对象b)对于我将对向量的元素进行的其他操作,它是他们更容易保持相同的顺序。

此外,我真的不想走在不断挑选和拒绝重复的街道上。很可能我会在向量中存储大量这些大对象,效率很关键,因为我希望每秒多次调用这种随机选择方法。

3 个答案:

答案 0 :(得分:6)

创建一个与现有向量相同的向量,该向量使用指向向量中元素的指针。随机地改变指针向量并从那里读取 - 这是低成本。

答案 1 :(得分:4)

您没有告诉我们您是想随机迭代整个数组,还是只需要随机选择一些元素。

我假设第一个案例。您需要额外的存储空间来进行簿记,无论如何您都需要线性时间进行洗牌。因此,创建一个排列,并保持其记忆存活,以便您可以按照自己的意愿重新调整它。使用C ++ 11:

#include <algorithm>
#include <random>
#include <numeric>

struct permutation
{
    permutation(size_t n) 
        : perm(n), g(std::random_device())
    {
        std::iota(perm.begin(), perm.end(), size_t(0));
    }

    void shuffle() { std::shuffle(perm.begin(), perm.end(), g); }

    size_t operator[](size_t n) const { return perm[n]; }

private:
    std::vector<size_t> perm;
    std::mt19937 g;
};

用法:

std::vector<huge_t> v;
...

permutation sigma(v.size());
sigma.shuffle();

const huge_t& x = v[sigma[0]];

...
sigma.shuffle(); // No extra allocation
const huge_t& y = v[sigma[0]];

您可以调整代码以使用C ++ 03 std::random_shuffle,但请注意,随机数生成器的保证非常少。

答案 2 :(得分:2)

我认为最简单的(也是效率最高的一种)解决方案是在您的std::vector<size_t>中创建vector<T>保留索引,或者将std::vector<T*>指针保存到您的vector std::random_shuffle。然后你可以使用size_t对其进行洗牌,迭代它并从原始向量中选择相应的元素。这样你就不会改变原始向量的顺序和改变指针,或{{1}}非常便宜