Reputation: 1577
Given a vector<T> vec{...}
what's the best way to extract its minimum, maximum and median assuming T is one of the numeric types? I know of std::nth_element
as well as std::minmax_element
but they seem to do redundant work if called one after another.
The best idea I came up with so far is to just call std::nth_element 3 times one after another. But this still needs 3N comparisons, right? Is there any way to reuse the partial sorting done in previous iterations?
Upvotes: 13
Views: 1579
Reputation: 106116
Another option is to specify a custom comparison for std::nth_element
, which captures the min and max. It will likely end up doing a lot more comparisons and branches, so this might be slower on some specific hardware, possibly depending on how much of your data is cached etc., so - as always - benchmark if you've reason to care, but for a non-empty vector
a
the technique looks like this:
int min = a[0], max = a[0];
std::nth_element(a.begin(), a.begin() + n, a.end(),
[&](int lhs, int rhs) {
min = std::min(min, std::min(lhs, rhs));
max = std::max(max, std::max(lhs, rhs));
return lhs < rhs;
});
For what little it's worth, on my (~10yo i5-660) HTPC using GCC 7.4 with 1 million random int
s between 0 and 1000, nth_element
takes about 36% longer with the min/max comparison than without.
Upvotes: 3
Reputation: 234715
Use std::nth_element
to partition which yields the median, then std::min_element
in the left half and std::max_element
in the right one.
If you need it to be faster than that then roll your own version based on std::nth_element
.
Upvotes: 12