forked from boostorg/algorithm
72 lines
3.0 KiB
Plaintext
72 lines
3.0 KiB
Plaintext
![]() |
[/ File indirect_sort.qbk]
|
||
|
|
||
|
[section:indirect_sort indirect_sort ]
|
||
|
|
||
|
[/license
|
||
|
Copyright (c) 2023 Marshall Clow
|
||
|
|
||
|
Distributed under the Boost Software License, Version 1.0.
|
||
|
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
]
|
||
|
|
||
|
There are times that you want a sorted version of a sequence, but for some reason or another, you don't really want to sort them. Maybe the elements in the sequence are non-copyable (or non-movable), or the sequence is const, or they're just really expensive to move around. An example of this might be a sequence of records from a database.
|
||
|
|
||
|
Nevertheless, you might want to sort them. That's where indirect sorting comes in. In a "normal" sort, the elements of the sequence to be sorted are shuffled in place. In indirect sorting, the elements are unchanged, but the sort algorithm returns to you a "permutation" of the elements that, when applied, will leave the elements in the sequence in a sorted order.
|
||
|
|
||
|
Say you have a sequence `[first, last)` of 1000 items that are expensive to swap:
|
||
|
```
|
||
|
std::sort(first, last); // ['O(N ln N)] comparisons and ['O(N ln N)] swaps (of the element type).
|
||
|
```
|
||
|
|
||
|
On the other hand, using indirect sorting:
|
||
|
```
|
||
|
auto permutation = boost::algorithm::indirect_sort(first, last); // ['O(N lg N)] comparisons and ['O(N lg N)] swaps (of size_t).
|
||
|
boost::algorithm::apply_permutation(first, last, perm.begin(), perm.end()); // ['O(N)] swaps (of the element type)
|
||
|
```
|
||
|
|
||
|
If the element type is sufficiently expensive to swap, then 10,000 swaps of size_t + 1000 swaps of the element_type could be cheaper than 10,000 swaps of the element_type.
|
||
|
|
||
|
Or maybe you don't need the elements to actually be sorted - you just want to traverse them in a sorted order:
|
||
|
```
|
||
|
auto permutation = boost::algorithm::indirect_sort(first, last);
|
||
|
for (size_t idx: permutation)
|
||
|
std::cout << first[idx] << std::endl;
|
||
|
```
|
||
|
|
||
|
|
||
|
More to come here ....
|
||
|
|
||
|
[heading interface]
|
||
|
|
||
|
The function `indirect_sort` a `vector<size_t>` containing the permutation necessary to put the input sequence into a sorted order. One version uses `std::less` to do the comparisons; the other lets the caller pass predicate to do the comparisons.
|
||
|
|
||
|
```
|
||
|
template <typename RAIterator>
|
||
|
std::vector<size_t> indirect_sort (RAIterator first, RAIterator last);
|
||
|
|
||
|
template <typename RAIterator, typename BinaryPredicate>
|
||
|
std::vector<size_t> indirect_sort (RAIterator first, RAIterator last, BinaryPredicate pred);
|
||
|
```
|
||
|
|
||
|
[heading Examples]
|
||
|
|
||
|
[heading Iterator Requirements]
|
||
|
|
||
|
`indirect_sort` requires random-access iterators.
|
||
|
|
||
|
[heading Complexity]
|
||
|
|
||
|
Both of the variants of `indirect_sort` run in ['O(N lg N)] time; they are not more (or less) efficient than `std::sort`. There is an extra layer of indirection on each comparison, but all off the swaps are done on values of type `size_t`
|
||
|
|
||
|
[heading Exception Safety]
|
||
|
|
||
|
[heading Notes]
|
||
|
|
||
|
[endsect]
|
||
|
|
||
|
[/ File indirect_sort.qbk
|
||
|
Copyright 2023 Marshall Clow
|
||
|
Distributed under the Boost Software License, Version 1.0.
|
||
|
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
|
||
|
]
|