编辑:Armin 删除了他的答案,所以我的答案似乎断章取义。让我们展开
tl;dr 不,STL 中没有将相同的 shuffle 应用于多个容器的函数。 STL 相当大,但不能做所有事情。对算法的具体要求太多了。你问的不是那种常见的做法。
但是,没有什么能阻止您编写自己的算法。例如,您可以复制算法shown on std::shuffle on cppreference.com (third version) 并对其进行修改。
#include <iterator>
template<class URBG, class RandomIt1, class RandomIt2>
static void SameShuffleToMany(URBG&& g, RandomIt1 first1, RandomIt1 last1, RandomIt2 first2) {
using diff_t = typename std::iterator_traits<RandomIt1>::difference_type;
using distr_t = std::uniform_int_distribution<diff_t>;
using param_t = typename distr_t::param_type;
distr_t D;
diff_t n = last1 - first1;
for (diff_t i = n-1; i > 0; --i) {
diff_t j = D(g, param_t(0, i));
std::swap(first1[i], first1[j]);
std::swap(first2[i], first2[j]);
}
}
哎呀,你甚至可以使用可变参数模板参数来并行处理超过 2 个容器。
但是,正如 cmets 中所建议的,有多种解决方案可以解决此问题。每个解决方案都有自己的优点和缺点。我在下面做了一个速度台。但是,Armin 和 Jamit 的解决方案将需要额外的内存来存储新的索引和重新排序输出的目标。
旧答案
我做了一些比较基准代码
#include <benchmark/benchmark.h>
#include <vector>
#include <algorithm>
#include <random>
#include <iostream>
static constexpr auto N = 1000;
static std::vector<int> CreateVector() {
std::vector<int> out;
out.reserve(N);
std::generate_n(back_inserter(out), N,
[gen = std::mt19937(std::random_device{}())] () mutable { return gen();}
);
return out;
}
static void BM_Original(benchmark::State& state) {
auto a = CreateVector();
auto b = a; // elementwise copy
for (auto _ : state) {
std::random_device rd;
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> rnd(0, a.size()-1);
for (int n = 0; n < a.size(); ++n) {
int m = rnd(gen);
std::swap(a[n], a[m]);
std::swap(b[n], b[m]);
}
}
if (!std::equal(cbegin(a), cend(a), cbegin(b)))
std::cout << "Vectors are not equal!\n";
}
// Register the function as a benchmark
BENCHMARK(BM_Original);
static void BM_Jamit(benchmark::State& state) {
auto a = CreateVector();
auto b = a; // elementwise copy
for (auto _ : state) {
std::vector<int> idx(N);
std::iota(begin(idx), end(idx), 0);
std::mt19937 g(std::random_device{}());
std::shuffle(begin(idx), end(idx), g);
std::vector<int> aout; aout.reserve(N);
std::transform(cbegin(idx), cend(idx), back_inserter(aout), [&](int i) { return a[i]; });
a = std::move(aout);
std::vector<int> bout; bout.reserve(N);
std::transform(cbegin(idx), cend(idx), back_inserter(aout), [&](int i) { return b[i]; });
b = std::move(bout);
}
if (!std::equal(cbegin(a), cend(a), cbegin(b)))
std::cout << "Vectors are not equal!\n";
}
// Register the function as a benchmark
BENCHMARK(BM_Jamit);
static void BM_Armin(benchmark::State& state) {
auto a = CreateVector();
auto b = a; // elementwise copy
for (auto _ : state) {
const unsigned int seedValue = std::random_device()();
std::mt19937 uniformRandomBitGenerator{};
uniformRandomBitGenerator.seed(seedValue);
std::shuffle(begin(a), end(a), uniformRandomBitGenerator);
uniformRandomBitGenerator.seed(seedValue);
std::shuffle(begin(b), end(b), uniformRandomBitGenerator);
}
if (!std::equal(cbegin(a), cend(a), cbegin(b)))
std::cout << "Vectors are not equal!\n";
}
// Register the function as a benchmark
BENCHMARK(BM_Armin);
#include <iterator>
template<class URBG, class RandomIt1, class RandomIt2>
static void SameShuffleToMany(URBG&& g, RandomIt1 first1, RandomIt1 last1, RandomIt2 first2) {
using diff_t = typename std::iterator_traits<RandomIt1>::difference_type;
using distr_t = std::uniform_int_distribution<diff_t>;
using param_t = typename distr_t::param_type;
distr_t D;
diff_t n = last1 - first1;
for (diff_t i = n-1; i > 0; --i) {
diff_t j = D(g, param_t(0, i));
std::swap(first1[i], first1[j]);
std::swap(first2[i], first2[j]);
}
}
static void BM_Mine(benchmark::State& state) {
auto a = CreateVector();
auto b = a; // elementwise copy
for (auto _ : state) {
std::mt19937 g{std::random_device{}()};
SameShuffleToMany(g, begin(a), end(a), begin(b));
}
if (!std::equal(cbegin(a), cend(a), cbegin(b)))
std::cout << "Vectors are not equal!\n";
}
// Register the function as a benchmark
BENCHMARK(BM_Mine);
BENCHMARK_MAIN();
得到的 CPU 时间为:
- 原始:108600 ns
- Jamit:76000 ns
- Armin:122000 ns
- 我的:102000 ns
link to QuickBench让我知道这是否适合你。我不认为那里的链接共享与 GodBolt 一样好。