Okay, now we’re going to start using the apply_permutation
function that we beat to death for first part of this week.
Suppose you are sorting a collection of objects with the property that copying and moving them is expensive. (Okay, so in practice, moving is not expensive, so let’s say that the object is not movable at all.) You want to minimize the number of copies.
The typical solution for this is to perform an indirect sort: Instead of moving expensive things around, use an inexpensive thing (like as an integer) to represent the expensive item, and sort the inexpensive things. Once you know where everything ends up, you can move the expensive things just once.
template<typename Iter, typename Compare> void sort_minimize_copies(Iter first, Iter last, Compare cmp) { using Diff = std::iterator_traits<Iter1>::difference_type; Diff length = last - first; std::vector<Diff> indices(length); std::iota(indices.begin(), indices.end(), static_cast<Diff>(0)); std::sort(indices.begin(), indices.end(), [&](Diff a, Diff b) { return cmp(first[a], first[b]); }); apply_permutation(first, last, indices.begin()); } template<typename Iter> void sort_minimize_copies(Iter first, Iter last) { return sort_minimize_copies(first, last, std::less<>()); }
We use std::iterator_traits
to tell us what to use to represent indices, then we create a vector of those indices. (The difference type is required to be an integral type, so we didn’t have to play any funny games like first - first
to get the null index. We could just write 0
.)
We then sort the indices by using the indices to reference the original collection. (We also provide an overload that sorts by <
.) This performs an indirect sort, where we are sorting the original collection, but doing so by mainpulating indices rather than the actual objects.
Once we have the indices we need, we can use the apply_permutation
function to rearrange the original items according to the indices.
We’ll wrap up next time with another kind of sorting.
0 comments