Spec-Zone.ru › C++

std::binary_search

Определён в заголовочном файле <algorithm>
template< class ForwardIt, class T >
bool binary_search( ForwardIt first, ForwardIt last,
                    const T& value );
(1) (до C++26)
(constexpr с C++20)
template< class ForwardIt, class T = typename std::iterator_traits
                                         <ForwardIt>::value_type >
constexpr bool binary_search( ForwardIt first, ForwardIt last,
                              const T& value );
(начиная с C++26)
template< class ForwardIt, class T, class Compare >
bool binary_search( ForwardIt first, ForwardIt last,
                    const T& value, Compare comp );
(2) (до C++26)
(constexpr с C++20)
template< class ForwardIt, class T = typename std::iterator_traits
                                         <ForwardIt>::value_type,
          class Compare >
constexpr bool binary_search( ForwardIt first, ForwardIt last,
                              const T& value, Compare comp );
(начиная с C++26)

Проверяет, встречается ли элемент, эквивалентный value, в разбитом на части диапазоне [first, last).

1) Эквивалентность проверяется с помощью operator<:

Если !bool(*iter < value) && !bool(value < *iter) имеет значение true для некоторого итератора iter в [first, last), возвращает true. В противном случае возвращает false.

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

  • Для любого элемента elem из [first, last) из bool(elem < value) не следует !bool(value < elem).
  • Элементы elem из [first, last) не разбиты на части относительно выражений bool(elem < value) и !bool(value < elem).
(до C++20)

Эквивалентно std::binary_search(first, last, value, std::less{}).

(начиная с C++20)
2) Эквивалентность проверяется с помощью comp:
Если !bool(comp(*iter, value)) && !bool(comp(value, *iter)) имеет значение true для некоторого итератора iter в [first, last), возвращает true. В противном случае возвращает false.
Если выполняется любое из следующих условий, поведение не определено:
  • Для любого элемента elem из [first, last) из bool(comp(elem, value)) не следует !bool(comp(value, elem)).
  • Элементы elem из [first, last) не разбиты на части относительно выражений bool(comp(elem, value)) и !bool(comp(value, elem)).

Параметры

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

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

boolpred(constType1&a,constType2&b);

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

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

Возвращаемое значение

true, если найден элемент, эквивалентный value, и false в противном случае.

Сложность

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

1) Не более \(\scriptsize \log_{2}(N)+O(1)\)log2(N)+O(1) сравнений с помощью value, используя operator<(до C++20)std::less{}(начиная с C++20).
2) Не более \(\scriptsize \log_{2}(N)+O(1)\)log2(N)+O(1) вызовов компаратора comp.

Однако, если ForwardIt не является LegacyRandomAccessIterator, количество приращений итератора линейно относительно \(\scriptsize N\)N.

Примечания

Хотя std::binary_search требует только, чтобы [first, last) был разбит на части, обычно этот алгоритм используется в тех случаях, когда [first, last) отсортирован, поэтому двоичный поиск корректен для любого value.

std::binary_search лишь проверяет, существует ли эквивалентный элемент. Чтобы получить итератор на этот элемент (если он существует), следует использовать std::lower_bound.

Макрос проверки функциональности Значение Стандарт Функция
__cpp_lib_algorithm_default_value_type 202403 (C++26) Инициализация списком для алгоритмов (1,2)

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

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

binary_search (1)
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type>
bool binary_search(ForwardIt first, ForwardIt last, const T& value)
{
    return std::binary_search(first, last, value, std::less{});
}
binary_search (2)
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type,
         class Compare>
bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    first = std::lower_bound(first, last, value, comp);
    return (!(first == last) and !(comp(value, *first)));
}

Пример

#include <algorithm>
#include <cassert>
#include <complex>
#include <iostream>
#include <vector>

int main()
{
    const auto haystack = {1, 3, 4, 5, 9};
    
    for (const auto needle : {1, 2, 3})
    {
        std::cout << "Searching for " << needle << '\n';
        if (std::binary_search(haystack.begin(), haystack.end(), needle))
            std::cout << "Found " << needle << '\n';
        else
            std::cout << "Not found!\n";
    }

    using CD = std::complex<double>;
    std::vector<CD> nums{{1, 1}, {2, 3}, {4, 2}, {4, 3}};
    auto cmpz = [](CD x, CD y){ return abs(x) < abs(y); };
    #ifdef __cpp_lib_algorithm_default_value_type
        assert(std::binary_search(nums.cbegin(), nums.cend(), {4, 2}, cmpz));
    #else
        assert(std::binary_search(nums.cbegin(), nums.cend(), CD{4, 2}, cmpz));
    #endif
}

Вывод:

Searching for 1
Found 1
Searching for 2
Not found!
Searching for 3
Found 3

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

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

DR Применён к Опубликованное поведение Корректное поведение
LWG 270 C++98 Compare должен был соответствовать требованиям Compare, а T должен был
быть LessThanComparable (требовался строгий слабый порядок)
требуется только разбиение на части;
разрешены гетерогенные сравнения
LWG 787 C++98 допускалось не более \(\scriptsize \log_{2}(N)+2\)log2(N)+2 сравнений исправлено на \(\scriptsize \log_{2}(N)+O(1)\)log2(N)+O(1)

См. также

equal_range
находит диапазон элементов, соответствующих заданному значению, с помощью двоичного поиска
(шаблон функции и объект-функция алгоритма)
ranges::equal_range
(C++20)
lower_bound
находит с помощью двоичного поиска первый элемент, не меньший заданного значения
(шаблон функции и объект-функция алгоритма)
ranges::lower_bound
(C++20)
upper_bound
находит с помощью двоичного поиска первый элемент, больший заданного значения
(шаблон функции и объект-функция алгоритма)
ranges::upper_bound
(C++20)
ranges::binary_search
(C++20)
определяет с помощью двоичного поиска, существует ли элемент в диапазоне
(объект-функция алгоритма)

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

Spec-Zone.ru

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