# std::ranges::minmax_element

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less > constexpr ranges::minmax_result<I> minmax_element( I first, S last, Comp comp = {}, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::forward_range R, class Proj = std::identity, std::indirect_strict_weak_order< std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less > constexpr ranges::minmax_result<ranges::borrowed_iterator_t<R>> minmax_element( R&& r, Comp comp = {}, Proj proj = {} ); | (2) | (C++20 起)

1) 寻找范围 `[first, last)` 中的最小与最大元素。
2) 同 (1) ，但以 `r` 为源范围，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

first, last | - | 指代待检验范围的迭代器-哨位对
r | - | 待检验范围
comp | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

### 返回值

由指向最小元素的迭代器作为第一元素，指向最大元素作为第二元素组成的对象。若范围为空则返回 {first, first} 。若数个元素等价于最小元素，则返回指向首个这种元素的迭代器。若数个元素等价于最大元素，则返回指向最后一个这种元素的迭代器。

### 复杂度

至多应用 max(floor((3/2)*(N−1)), 0) 次比较和两倍次数的投影，其中 N = ranges::distance(first, last) 。

### 可能的实现

    struct minmax_element_fn {
      template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
               std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
      constexpr ranges::minmax_result<I> operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
      {
        auto min = first, max = first;

        if (first == last || ++first == last) {
          return {min, max};
        }

        if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *min))) {
          min = first;
        } else {
          max = first;
        }

        while (++first != last) {
          auto i = first;
          if (++first == last) {
            if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *min))) {
                min = i;
            }
            else if (!(std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *max)))) {
                max = i;
            }
            break;
          } else {
            if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *i))) {
              if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *min))) {
                min = first;
              }
              if (!(std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *max)))) {
                max = i;
              }
            } else {
              if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *min))) {
                min = i;
              }
              if (!(std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *max)))) {
                max = first;
              }
            }
          }
        }
        return {min, max};
      }

      template<ranges::forward_range R, class Proj = std::identity,
               std::indirect_strict_weak_order<
                   std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr ranges::minmax_result<ranges::borrowed_iterator_t<R>>
      operator()(R&& r, Comp comp = {}, Proj proj = {}) const
      {
        return (*this)(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
      }
    };

    inline constexpr minmax_element_fn minmax_element;

### 示例

    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <cmath>

    int main() {
        const auto v = { 3, 9, 1, 4, 2, 5, 9 };
        const auto [min, max] = std::ranges::minmax_element(v);

        std::cout << "min = " << *min << ", max = " << *max << '\n';
    }

输出：

    min = 1, max = 9

### 参阅

ranges::min_element (C++20) | 返回范围中的最小元素 (niebloid)
ranges::max_element (C++20) | 返回范围中的最大元素 (niebloid)
ranges::minmax (C++20) | 返回两个元素的较小和较大者 (niebloid)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)