Spec-Zone.ru › C++

std::upper_bound

Определено в заголовке <algorithm>
(1)
template< class ForwardIt, class T >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );
(до C++20)
template< class ForwardIt, class T >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last,
                                 const T& value );
(с C++20)
(2)
template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last,
                       const T& value, Compare comp );
(до C++20)
template< class ForwardIt, class T, class Compare >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last,
                                 const T& value, Compare comp );
(с C++20)

Возвращает итератор, указывающий на первый элемент в диапазоне [first, last) такой, что value < element (или comp(value, element)) является true (т.е., строго больше value), или last , если такой элемент не найден.

Диапазон [first, last) должен быть разбит относительно выражения !(value < element) или !comp(value, element), т. е., все элементы, для которых выражение истинно true, должны предшествовать всем элементам, для которых выражение истинно false. Полностью отсортированный диапазон соответствует этому критерию.

Первый вариант использует оператор < для сравнения элементов, второй вариант использует заданную функцию сравнения comp.

Параметры

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

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

bool pred(const Type1 &a, const Type2 &b);

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

Требования к типу
-ForwardIt должно соответствовать требованиям итератора LegacyForwardIterator.
-Compare должно соответствовать требованиям бинарного предиката. Не требуется соответствовать Compare.

Значение результата

Итератор, указывающий на первый элемент в диапазоне [first, last) такой, что value < element (или comp(value, element)) является true, или last , если такой элемент не найден.

Сложность

Количество выполненных сравнений логарифмически зависит от расстояния между first и last (максимум log2(last - first) + O(1) сравнений).

Однако для не-LegacyRandomAccessIterators количество инкрементов итераторов линейно. Обратите внимание, что std::map, std::multimap, std::set, и std::multiset итераторы не являются случайного доступа, поэтому следует предпочитать их функции-члены upper_bound.

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

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

upper_bound (1)
template<class ForwardIt, class T>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);
 
    while (count > 0)
    {
        it = first; 
        step = count / 2; 
        std::advance(it, step);
 
        if (!(value < *it))
        {
            first = ++it;
            count -= step + 1;
        } 
        else
            count = step;
    }
 
    return first;
}
upper_bound (2)
template<class ForwardIt, class T, class Compare>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);
 
    while (count > 0)
    {
        it = first; 
        step = count / 2;
        std::advance(it, step);
 
        if (!comp(value, *it))
        {
            first = ++it;
            count -= step + 1;
        } 
        else
            count = step;
    }
 
    return first;
}

Пример

#include <algorithm>
#include <iostream>
#include <vector>
 
struct PriceInfo { double price; };
 
int main()
{
    const std::vector<int> data{1, 2, 4, 5, 5, 6};
 
    for (int i = 0; i < 7; ++i)
    {
        // Search first element that is greater than i
        auto upper = std::upper_bound(data.begin(), data.end(), i);
 
        std::cout << i << " < ";
        upper != data.end()
            ? std::cout << *upper << " at index " << std::distance(data.begin(), upper)
            : std::cout << "not found";
        std::cout << '\n';
    }
 
    std::vector<PriceInfo> prices{{100.0}, {101.5}, {102.5}, {102.5}, {107.3}};
 
    for (double to_find : {102.5, 110.2})
    {
        auto prc_info = std::upper_bound(prices.begin(), prices.end(), to_find,
            [](double value, const PriceInfo& info)
            {
                return value < info.price;
            });
 
        prc_info != prices.end()
            ? std::cout << prc_info->price << " at index " << prc_info - prices.begin()
            : std::cout << to_find << " not found";
        std::cout << '\n';
    }
}

Вывод:

0 < 1 at index 0
1 < 2 at index 1
2 < 4 at index 2
3 < 4 at index 2
4 < 5 at index 3
5 < 6 at index 5
6 < not found 
107.3 at index 4
110.2 not found

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

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

DR Применён к Опубликованное поведение Корректное поведение
LWG 270 C++98 Compare должно было соответствовать Compare, а T должно было
быть LessThanComparable (требовалась строгая слабая упорядоченность)
требуется только разбиение;
разрешены разнородные сравнения
LWG 384 C++98 разрешалось не более log(last - first) + 1 сравнений исправлено до log2(last - first) + O(1)
LWG 577 C++98 last не могло быть возвращено разрешено

См. также

equal_range
возвращает диапазон элементов, соответствующих определенному ключу
(шаблон функции)
lower_bound
возвращает итератор на первый элемент, не меньший, чем заданное значение
(шаблон функции)
partition
делит диапазон элементов на две группы
(шаблон функции)
partition_point
(C++11)
находит точку разбиения разбиеного диапазона
(шаблон функции)
ranges::upper_bound
(C++20)
возвращает итератор на первый элемент, больший, чем определенное значение
(niebloid)
upper_bound
возвращает итератор на первый элемент, больший, чем заданный ключ
(функция-член std::set<Key,Compare,Allocator>)
upper_bound
возвращает итератор на первый элемент, больший, чем заданный ключ
(функция-член std::multiset<Key,Compare,Allocator>)

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

Spec-Zone.ru

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