交换向量的值和索引

时间:2015-10-01 20:22:31

标签: c++ vector swap

我有一个std::vector<int>,其中包含从0到N的连续洗牌值,并且希望尽可能有效地交换每个值及其在向量中的位置。

示例:

v[6] = 3;

变为

v[3] = 6;

这是一个简单的问题,但我不知道如何处理它以使其变得微不足道,最重要的是,非常快。非常感谢你的建议。

1 个答案:

答案 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

对哪一个更快的基准测试留给读者的练习;)