我有一个std::vector<int>
,其中包含从0到N的连续洗牌值,并且希望尽可能有效地交换每个值及其在向量中的位置。
示例:
v[6] = 3;
变为
v[3] = 6;
这是一个简单的问题,但我不知道如何处理它以使其变得微不足道,最重要的是,非常快。非常感谢你的建议。
答案 0 :(得分:0)
在编译时给定N
并且给定数组仅包含[0,N)
中的每个索引一次,
它是相对直接的(只要它不必就地,如上面的评论所述):
构造一个新数组,以便v'[n] = find_index(v, n)
并将其分配给旧数组。
在这里,我使用std::index_sequence
的可变参数模板将其转换为单个作业:
template<typename T, std::size_t N>
std::size_t find_index(const std::array<T,N>& arr, std::size_t index) {
return static_cast<std::size_t>(std::distance(arr.begin(), std::find(arr.begin(), arr.end(), index)));
}
template<typename T, std::size_t N, std::size_t... Index>
void swap_index_value(std::array<T,N>& arr, std::index_sequence<Index...> seq){
arr = { find_index(arr, Index)... };
}
template<typename Integer, std::size_t N>
void swap_index_value(std::array<Integer,N>& arr) {
swap_index_value(arr, std::make_index_sequence<N>{});
}
这种复杂性看起来并不好看。在find_index(arr, n)
中为每个n调用[0,N)
总计将进行N *(N + 1)/ 2次比较(std::sort
仅取N * log(N))。
但是,由于我们知道数组中存在每个索引,我们可以填写索引数组 当我们遍历原始数组时,假设T是一个整数类型,我们可以跳过一些std :: size_t&lt; - &gt; T转换也是如此:
template<typename T, std::size_t N>
void swap_index_value(std::array<T,N>& arr){
std::array<T, N> indices;
for (T i = 0; i < N; ++i)
indices[arr[i]] = i;
arr = indices;
}
我们仍然使用两倍的空间并对我们的数组进行一些随机排序的写入, 但基本上我们只有2 * N分配,代码比以前简单。
或者,如果我们保留副本以进行查找,我们也可以std::sort
template<typename T, std::size_t N>
void swap_index_value(std::array<T,N>& arr){
std::sort(arr.begin(), arr.end(), [copy = arr](const T& lhs, const T& rhs) {
return copy[lhs] < copy[rhs];
});
}
第一个版本here, 第二版here, std :: sort version here
对哪一个更快的基准测试留给读者的练习;)