std::minmax_element(3)
β¨ std::minmax_element β¨
okay bestie, so this is std::minmax_element from the C++ standard library, and it is literally the moment you stop calling std::min_element and std::max_element separately like some kind of rookie. it's giving efficiency. it's giving main character algorithm. let's get into it π«Ά
πΈ SYNOPSIS πΈ
so this little icon lives in <algorithm> and it has four overloads, which is a lot but we're gonna slay through them together:
template< class ForwardIt >
std::pair<ForwardIt, ForwardIt>
minmax_element( ForwardIt first, ForwardIt last );
(1) (since C++11) (constexpr since C++17)
template< class ExecutionPolicy, class ForwardIt >
std::pair<ForwardIt, ForwardIt>
minmax_element( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last );
(2) (since C++17)
template< class ForwardIt, class Compare >
std::pair<ForwardIt, ForwardIt>
minmax_element( ForwardIt first, ForwardIt last,
Compare comp );
(3) (since C++11) (constexpr since C++17)
template< class ExecutionPolicy, class ForwardIt, class Compare >
std::pair<ForwardIt, ForwardIt>
minmax_element( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last,
Compare comp );
(4) (since C++17)
bestie it literally just finds the smallest and greatest element in the range [first, last). two for the price of one. we love a multitasking king π
- overloads 1 and 3: elements are compared using
operator<(until C++20) orstd::less{}(since C++20). lowkey glow-up from the standard, ngl. - overload 3: elements are compared using the comparison function
comp. - overloads 2 and 4: same as 1 and 3, but executed according to
policy. the tea here is these overloads participate in overload resolution only if:std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>istrue(until C++20)std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>istrue(since C++20)
π PARAMETERS π
first,lastβ forward iterators defining the range to examine. these are your besties that tell the algorithm where to start and where to stop.policyβ the execution policy to use. see execution policy for details, iykyk.cmpβ comparison function object (i.e. an object that satisfies the requirements ofCompare) which returnstrueif the first argument is less than the second.
the signature of the comparison function should be equivalent to the following:
bool cmp(const Type1& a, const Type2& b);
while the signature does not need to have const&, the function must not modify the objects passed to it and must be able to accept all values of type (possibly const) Type1 and Type2 regardless of value category. so Type1& is not allowed, nor is Type1 unless for Type1 a move is equivalent to a copy (since C++11). the types Type1 and Type2 must be such that an object of type ForwardIt can be dereferenced and then implicitly converted to both of them. no cap, this is important.
π¦ TYPE REQUIREMENTS π¦
ForwardItmust meet the requirements of LegacyForwardIterator.
π RETURN VALUE π
a std::pair consisting of:
- an iterator to the smallest element as the first element
- an iterator to the greatest element as the second element
if the range is empty, it returns std::make_pair(first, first). literally just hands you back where you started. respectful. π
if several elements are equivalent to the smallest element, the iterator to the first such element is returned. if several elements are equivalent to the largest element, the iterator to the last such element is returned. periodt. that last part matters, bestie, remember it.
β COMPLEXITY β
given N as std::distance(first, last):
- overloads 1, 2: at most
max(β3/2 (N-1)β, 0)comparisons usingoperator<(until C++20) orstd::less{}(since C++20). - overloads 3, 4: at most
max(β3/2 (N-1)β, 0)applications of the comparison functioncomp.
so like, the math is max(β3/2 (N-1)β, 0) and it's giving big brain energy. we're doing the 3/2 thing so we don't do 2N comparisons like some kinda clown. π
π₯ EXCEPTIONS π₯
the overloads with a template parameter named ExecutionPolicy report errors as follows:
- if execution of a function invoked as part of the algorithm throws an exception and
ExecutionPolicyis one of the standard policies,std::terminateis called. for any otherExecutionPolicy, the behavior is implementation-defined. π don't play with this. - if the algorithm fails to allocate memory,
std::bad_allocis thrown.
π POSSIBLE IMPLEMENTATION π
okay so here's how the girlies on the standard committee might implement it. bestie, this is possible implementation, not guaranteed, but it's so iconic I have to show you:
minmax_element (no comp)
template<class ForwardIt>
std::pair<ForwardIt, ForwardIt>
minmax_element(ForwardIt first, ForwardIt last)
{
using value_type = typename std::iterator_traits<ForwardIt>::value_type;
return std::minmax_element(first, last, std::less<value_type>());
}
minmax_element (with comp)
template<class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt>
minmax_element(ForwardIt first, ForwardIt last, Compare comp)
{
auto min = first, max = first;
if (first == last || ++first == last)
return {min, max};
if (comp(*first, *min))
min = first;
else
max = first;
while (++first != last)
{
auto i = first;
if (++first == last)
{
if (comp(*i, *min))
min = i;
else if (!(comp(*i, *max)))
max = i;
break;
}
else
{
if (comp(*first, *i))
{
if (comp(*first, *min))
min = first;
if (!(comp(*i, *max)))
max = i;
}
else
{
if (comp(*i, *min))
min = i;
if (!(comp(*first, *max)))
max = first;
}
}
}
return {min, max};
}
like, the way this eats. the way it processes elements in pairs to keep comparisons down. obsessed. π§
πΈ NOTES πΈ
this algorithm is different from std::make_pair(std::min_element(), std::max_element()). not only in efficiency, but also in that this algorithm finds the last biggest element while std::max_element finds the first biggest element. so if you're out here assuming they're the same, bestie, no. they are not. π
π EXAMPLE π
// Run this code
#include <algorithm>
#include <iostream>
int main()
{
const auto v = {3, 9, 1, 4, 2, 5, 9};
const auto [min, max] = std::minmax_element(begin(v), end(v));
std::cout << "min = " << *min << ", max = " << *max << '\n';
}
Output:
min = 1, max = 9
look at that. structured bindings. clean. iconic. no notes. π«Ά
π SEE ALSO π
min_elementβ returns the smallest element in a range (function template)max_elementβ returns the largest element in a range (function template)ranges::minmax_elementβ returns the smallest and the largest elements in a range (C++20) (niebloid)
bestie reminder: this page is from the C++ Standard Library, manualstd::minmax_element(3), sourcehttp://cppreference.com, date2024.06.10. go forth and minmax. π
π that's the whole page, bestie β every overload, every parameter, every yield and caveat, exactly as it was. π from http://cppreference.com Β· 2024.06.10 Β· std::minmax_element(3)
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms