For the case where you are interested in proxy sorting (sorting an index list), you may want to implement a more flexible algorithm that allows you to deal with containers which do not support random access (such as std::list
). For example:
#include <algorithm>
#include <iostream>
#include <list>
#include <numeric>
#include <vector>
template <typename Container>
auto sorted_indices(const Container& c) {
std::vector<typename Container::size_type> indices(c.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(), [&c](auto lhs, auto rhs) {
return (*(std::next(c.begin(), lhs)) < *(std::next(c.begin(), rhs)));
});
return indices;
}
template <typename Container, typename Indices>
auto display_sorted(const Container& c, const Indices& indices) {
std::cout << "sorted: ";
for (auto&& index : indices) {
std::cout << *(std::next(c.begin(), index)) << " ";
}
std::cout << std::endl;
}
template <typename Container>
auto display_sorted(const Container& c) {
return display_sorted(c, sorted_indices(c));
}
template <typename Container>
auto display(const Container& c) {
std::cout << "as provided: ";
for (auto&& ci : c) std::cout << ci << " ";
std::cout << std::endl;
}
int main() {
// random access
const std::vector<int> a{9, 5, 2, 3, 1, 6, 4};
display(a);
display_sorted(a);
display(a);
std::cout << "---\n";
// no random access
const std::list<int> b{9, 5, 2, 3, 1, 6, 4};
display(b);
display_sorted(b);
display(b);
}
Sample run:
$ clang++ example.cpp -std=c++17 -Wall -Wextra
$ ./a.out
as provided: 9 5 2 3 1 6 4
sorted: 1 2 3 4 5 6 9
as provided: 9 5 2 3 1 6 4
---
as provided: 9 5 2 3 1 6 4
sorted: 1 2 3 4 5 6 9
as provided: 9 5 2 3 1 6 4
As you would expect, relying on proxy sorting could have important performance implications. For example: every time you want to traverse in order, you will possibly incur cache misses. In addition, the traversal will have the same complexity as the underlying container for random access: In the case of std::vector
, std::next(v.begin(), n)
is O(1)
, but in the case of std::list
, std::next(l.begin(), n)
is O(n)
.