Swap values and indexes of a vector

夙愿已清 提交于 2019-12-08 01:36:53

问题


I have a std::vector<int> with contiguous shuffled values from 0 to N and want to swap, as efficiently as possible, each value with its position in the vector.

Example:

v[6] = 3;

becomes

v[3] = 6;

This is a simple problem, but I do not know how to handle it in order to make it trivial and, above all, very fast. Thank you very much for your suggestions.


回答1:


Given N at compile time and given the array contains each index in [0,N) exactly once, it's relatively straight forward (as long as it doesn't have to be in-place, as mentioned in the comments above) :

Construct a new array so that v'[n] = find_index(v, n) and assign it to the old one.

Here I used variadic templates with std::index_sequence to roll it into a single assignment:

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>{});
}

The complexity of this is does not look great though. Calling find_index(arr, n) for each n in [0,N) will take N * (N+1) / 2 comparisons total (std::sort would only take N * log(N)).

However, since we know each index is present in the array, we could just fill out an array of indices as we walk over the original array, and assuming T is an integral type we can skip some std::size_t <-> T conversions, too:

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;
}

We're still using twice the space and doing some randomly ordered writes to our array, but essentially we're down to 2*N assignments, and the code is simpler than before.

Alternatively, we could also std::sort if we keep a copy to do lookups in:

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];
    });
}

First version here, second version here, std::sort version here

Benchmarking which one is faster is left as an exercise to the reader ;)



来源:https://stackoverflow.com/questions/32896226/swap-values-and-indexes-of-a-vector

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!