我正在寻找一种有效的方法,以随机顺序选择对std::vector<T>
的每个元素的访问,而不需要重新调整或复制它们,即不使用std::random_shuffle
并确保仅选择每个元素一旦。
我不想复制或重新调整为a)T
的每个实例都可能是一个非常大的对象b)对于我将对向量的元素进行的其他操作,它是他们更容易保持相同的顺序。
此外,我真的不想走在不断挑选和拒绝重复的街道上。很可能我会在向量中存储大量这些大对象,效率很关键,因为我希望每秒多次调用这种随机选择方法。
答案 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}}非常便宜