Spec-Zone.ru › C++

std::nth_element

Определён в заголовке <algorithm>
template< class RandomIt >
void nth_element( RandomIt first, RandomIt nth, RandomIt last );
(1) (constexpr начиная с C++20)
template< class ExecutionPolicy, class RandomIt >
void nth_element( ExecutionPolicy&& policy,
                  RandomIt first, RandomIt nth, RandomIt last );
(2) (начиная с C++17)
template< class RandomIt, class Compare >
void nth_element( RandomIt first, RandomIt nth, RandomIt last,
                  Compare comp );
(3) (constexpr начиная с C++20)
template< class ExecutionPolicy, class RandomIt, class Compare >
void nth_element( ExecutionPolicy&& policy,
                  RandomIt first, RandomIt nth, RandomIt last,
                  Compare comp );
(4) (начиная с C++17)

nth_element переставляет элементы в [first, last) так, что после перестановки выполняются следующие условия:

  • Элемент, на который указывает nth, заменяется тем элементом, который находился бы на этой позиции, если бы [first, last) был отсортирован.
  • Для каждого итератора i в [first, nth) и каждого итератора j в [nth, last) выполняется следующее условие:
1,2) bool(*j < *i)(до C++20)std::less{}(*j, *i)(начиная с C++20) является false.
3,4) bool(comp(*j, *i)) является false.
1) Элементы гипотетически сортируются относительно operator<(до C++20)std::less{}(начиная с C++20).
3) Элементы гипотетически сортируются относительно comp.
2,4) То же, что и (1,3), но выполняется в соответствии с policy.
Эти перегрузки участвуют в разрешении перегрузки, только если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с C++20)

Поведение не определено, если выполняется хотя бы одно из следующих условий:

  • [first, nth) или [nth, last) не является допустимым диапазоном.
  • Тип *first не удовлетворяет требованиям Swappable.
(до C++11)
  • RandomIt не удовлетворяет требованиям ValueSwappable.
  • Тип *first не удовлетворяет требованиям MoveConstructible.
  • Тип *first не удовлетворяет требованиям MoveAssignable.
(начиная с C++11)

Параметры

first, last - пара итераторов, задающая диапазон элементов для частичной сортировки
nth - итератор произвольного доступа, задающий точку разделения при сортировке
policy - политика выполнения, которую следует использовать
comp - объект функционального типа для сравнения (то есть объект, удовлетворяющий требованиям Compare), который возвращает ​true, если первый аргумент меньше второго (то есть расположен перед ним).

Сигнатура функции сравнения должна быть эквивалентна следующей:

boolcmp(constType1&a,constType2&b);

Хотя в сигнатуре не обязательно указывать const&, функция не должна изменять переданные ей объекты и должна принимать любые значения типа (возможно, const) Type1 и Type2 независимо от категории значения (поэтому Type1& не допускается, как и Type1, если только для Type1 перемещение не эквивалентно копированию(начиная с C++11)).
Типы Type1 и Type2 должны быть такими, чтобы объект типа RandomIt можно было разыменовать и неявно преобразовать к обоим этим типам. ​

Требования к типам
-RandomIt должен удовлетворять требованиям LegacyRandomAccessIterator.
-Compare должен удовлетворять требованиям Compare.

Сложность

Пусть \(\scriptsize N\)N — это last - first:

1) В среднем \(\scriptsize O(N)\)O(N) сравнений с использованием operator<(до C++20)std::less{}(начиная с C++20).
2) \(\scriptsize O(N)\)O(N) сравнений с использованием operator<(до C++20)std::less{}(начиная с C++20) и \(\scriptsize O(N \cdot \log(N))\)O(N·log(N)) обменов.
3) В среднем \(\scriptsize O(N)\)O(N) вызовов компаратора comp.
4) \(\scriptsize O(N)\)O(N) вызовов компаратора comp и \(\scriptsize O(N \cdot \log(N))\)O(N·log(N)) обменов.

Исключения

Перегрузки с параметром шаблона с именем ExecutionPolicy сообщают об ошибках следующим образом:

  • Если при выполнении функции, вызванной в ходе работы алгоритма, возникает исключение и ExecutionPolicy является одной из стандартных политик, вызывается std::terminate. Для любой другой ExecutionPolicy поведение определяется реализацией.
  • Если алгоритму не удаётся выделить память, генерируется исключение std::bad_alloc.

Возможная реализация

См. также реализации в libstdc++, libc++ и MSVC STL.

Примечания

Обычно используется алгоритм Introselect, хотя допускается использовать и другие алгоритмы выбора с подходящей средней сложностью.

Пример

#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>

void printVec(const std::vector<int>& vec)
{
    std::cout << "v = {";
    for (char sep[]{0, ' ', 0}; const int i : vec)
        std::cout << sep << i, sep[0] = ',';
    std::cout << "};\n";
}

int main()
{
    std::vector<int> v{5, 10, 6, 4, 3, 2, 6, 7, 9, 3};
    printVec(v);
    
    auto m = v.begin() + v.size() / 2;
    std::nth_element(v.begin(), m, v.end());
    std::cout << "\nThe median is " << v[v.size() / 2] << '\n';
    // The consequence of the inequality of elements before/after the Nth one:
    assert(std::accumulate(v.begin(), m, 0) < std::accumulate(m, v.end(), 0));
    printVec(v);
    
    // Note: comp function changed
    std::nth_element(v.begin(), v.begin() + 1, v.end(), std::greater{});
    std::cout << "\nThe second largest element is " << v[1] << '\n';
    std::cout << "The largest element is " << v[0] << '\n';
    printVec(v);
}

Возможный вывод:

v = {5, 10, 6, 4, 3, 2, 6, 7, 9, 3};

The median is 6
v = {3, 2, 3, 4, 5, 6, 10, 7, 9, 6};

The second largest element is 9
The largest element is 10
v = {10, 9, 6, 7, 6, 3, 5, 4, 3, 2};

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроспективно к ранее опубликованным стандартам C++.

DR Применяется к Опубликованное поведение Корректное поведение
LWG 2150 C++98 после перестановки требовалось, чтобы только один элемент перед nth
был не больше одного элемента после nth
требование было
исправлено
LWG 2163 C++98 перегрузка (1) использовала для сравнения элементов operator> заменён на operator<
P0896R4 C++98 [first, nth) и [nth, last)
не обязаны были быть допустимыми диапазонами
поведение не определено,
если любой из них недопустим

См. также

max_element
возвращает наибольший элемент в диапазоне
(шаблон функции и объект-функция алгоритма)
ranges::max_element
(C++20)
min_element
возвращает наименьший элемент в диапазоне
(шаблон функции и объект-функция алгоритма)
ranges::min_element
(C++20)
partial_sort_copy
копирует и частично сортирует диапазон элементов
(шаблон функции и объект-функция алгоритма)
ranges::partial_sort_copy
(C++20)
stable_sort
сортирует диапазон элементов, сохраняя относительный порядок эквивалентных элементов
(шаблон функции и объект-функция алгоритма)
ranges::stable_sort
(C++20)
sort
сортирует диапазон элементов
(шаблон функции и объект-функция алгоритма)
ranges::sort
(C++20)
ranges::nth_element
(C++20)
находит N-й элемент, который находился бы на этой позиции после сортировки диапазона
(объект-функция алгоритма)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/nth_element

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API