Spec-Zone.ru › C++

std::equal_range

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

Возвращает диапазон, содержащий все элементы, эквивалентные value в диапазоне [first, last).

Диапазон [first, last) должен быть хотя бы частично упорядоченным относительно value, т.е. он должен удовлетворять всем следующим требованиям:

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

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

Возвращаемый диапазон определяется двумя итераторами, один из которых указывает на первый элемент, который не меньше value, а другой — на первый элемент, больший value. Первый итератор можно альтернативно получить с помощью std::lower_bound(), второй — с помощью std::upper_bound().

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

Параметры

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

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

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

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

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

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

A std::pair , содержащий пару итераторов, определяющих требуемый диапазон. Первый указывает на первый элемент, который не меньше value, а второй — на первый элемент, больший value.

Если нет элементов, не меньших value, last возвращается в качестве первого элемента. Аналогично, если нет элементов, больших value, last возвращается в качестве второго элемента.

Сложность

Количество выполненных сравнений логарифмично по отношению к расстоянию между first и last (не более 2 * log2(last - first) + O(1) сравнений). Однако для не-LegacyRandomAccessIterators количество инкрементов итераторов линейно. Отметим, что std::set и std::multiset итераторы не являются случайным доступом, и поэтому предпочтительнее использовать их члены std::set::equal_range (соответственно std::multiset::equal_range).

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

equal_range (1)
template<class ForwardIt, class T>
std::pair<ForwardIt, ForwardIt> 
    equal_range(ForwardIt first, ForwardIt last, const T& value)
{
    return std::make_pair(std::lower_bound(first, last, value),
                          std::upper_bound(first, last, value));
}
equal_range (2)
template<class ForwardIt, class T, class Compare>
std::pair<ForwardIt, ForwardIt>
    equal_range(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    return std::make_pair(std::lower_bound(first, last, value, comp),
                          std::upper_bound(first, last, value, comp));
}

Пример

#include <algorithm>
#include <iostream>
#include <vector>
 
struct S
{
    int number;
    char name;
    // note: name is ignored by this comparison operator
    bool operator<(const S& s) const { return number < s.number; }
};
 
struct Comp
{
    bool operator()(const S& s, int i) const { return s.number < i; }
    bool operator()(int i, const S& s) const { return i < s.number; }
};
 
int main()
{
    // note: not ordered, only partitioned w.r.t. S defined below
    const std::vector<S> vec{{1, 'A'}, {2, 'B'}, {2, 'C'},
                             {2, 'D'}, {4, 'G'}, {3, 'F'}};
    const S value{2, '?'};
 
    std::cout << "Compare using S::operator<(): ";
    const auto p = std::equal_range(vec.begin(), vec.end(), value);
 
    for (auto i = p.first; i != p.second; ++i)
        std::cout << i->name << ' ';
 
    std::cout << "\n" "Using heterogeneous comparison: ";
    const auto p2 = std::equal_range(vec.begin(), vec.end(), 2, Comp{});
 
    for (auto i = p2.first; i != p2.second; ++i)
        std::cout << i->name << ' ';
    std::cout << '\n';
}

Вывод:

Compare using S::operator<(): B C D 
Using heterogeneous comparison: B C D

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

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

DR Применено к Поведение, как опубликовано Правильное поведение
LWG 270 C++98 Compare должно было удовлетворять Compare, а T должно было быть LessThanComparable (требовалось строгое слабое упорядочение) требуется только разделение;
разрешены гетерогенные сравнения
LWG 384 C++98 разрешалось не более 2 * log(last - first) + 1 сравнений, что не реализуемо[1] исправлено на
2 * log2(last - first) + O(1)
  1. Применение equal_range к диапазону из одного элемента требует 2 сравнений, но согласно требованиям к сложности допускается не более 1 сравнения.

См. также

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

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

Spec-Zone.ru

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