Namespaces
Variants

std:: equal_range

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
equal_range
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Definido en el encabezado <algorithm>
(1)
template < class ForwardIt, class T >

std:: pair < ForwardIt, ForwardIt >

equal_range ( ForwardIt first, ForwardIt last, const T & value ) ;
(constexpr desde C++20)
(hasta C++26)
template < class ForwardIt, class T = typename std:: iterator_traits

< ForwardIt > :: value_type >
constexpr std:: pair < ForwardIt, ForwardIt >

equal_range ( ForwardIt first, ForwardIt last, const T & value ) ;
(desde C++26)
(2)
template < class ForwardIt, class T, class Compare >

std:: pair < ForwardIt, ForwardIt >
equal_range ( ForwardIt first, ForwardIt last,

const T & value, Compare comp ) ;
(constexpr desde C++20)
(hasta C++26)
template < class ForwardIt, class T = typename std:: iterator_traits

< ForwardIt > :: value_type ,
class Compare >
constexpr std:: pair < ForwardIt, ForwardIt >
equal_range ( ForwardIt first, ForwardIt last,

const T & value, Compare comp ) ;
(desde C++26)

Devuelve un rango que contiene todos los elementos equivalentes a value en el rango particionado [ first , last ) .

1) La equivalencia se verifica utilizando operator < :

Devuelve los resultados de std:: lower_bound ( first, last, value ) y std:: upper_bound ( first, last, value ) .

Si se satisface alguna de las siguientes condiciones, el comportamiento es indefinido:

  • Para cualquier elemento elem de [ first , last ) , bool ( elem < value ) no implica ! bool ( value < elem ) .
  • Los elementos elem de [ first , last ) no están particionados con respecto a las expresiones bool ( elem < value ) y ! bool ( value < elem ) .
(hasta C++20)

Equivalente a std :: equal_range ( first, last, value, std:: less { } ) .

(desde C++20)
2) La equivalencia se verifica utilizando comp :
Devuelve los resultados de std:: lower_bound ( first, last, value, comp ) y std:: upper_bound ( first, last, value, comp ) .
Si se satisface cualquiera de las siguientes condiciones, el comportamiento es indefinido:
  • Para cualquier elemento elem de [ first , last ) , bool ( comp ( elem, value ) ) no implica ! bool ( comp ( value, elem ) ) .
  • Los elementos elem de [ first , last ) no están particionados con respecto a las expresiones bool ( comp ( elem, value ) ) y ! bool ( comp ( value, elem ) ) .

Contenidos

Parámetros

first, last - el par de iteradores que define el rango particionado de elementos a examinar
value - valor contra el cual comparar los elementos
comp - predicado binario que retorna ​ true si el primer argumento está ordenado antes del segundo.

La firma de la función predicado debe ser equivalente a:

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

Aunque la firma no necesita tener const & , la función no debe modificar los objetos pasados y debe poder aceptar todos los valores de tipo (posiblemente const) Type1 y Type2 independientemente de la categoría de valor (por lo tanto, Type1 & no está permitido , ni tampoco Type1 a menos que para Type1 un movimiento sea equivalente a una copia (desde C++11) ).
Los tipos Type1 y Type2 deben ser tales que un objeto de tipo T pueda convertirse implícitamente a ambos Type1 y Type2 , y un objeto de tipo ForwardIt pueda ser desreferenciado y luego convertido implícitamente a ambos Type1 y Type2 . ​

Requisitos de tipo
-
ForwardIt debe cumplir con los requisitos de LegacyForwardIterator .
-
Compare debe cumplir con los requisitos de BinaryPredicate . No se requiere que satisfaga Compare .

Valor de retorno

Un std::pair que contiene un par de iteradores, donde

  • first es un iterador al primer elemento del rango [ first , last ) no ordenado antes de value (o last si no se encuentra tal elemento), y
  • second es un iterador al primer elemento del rango [ first , last ) ordenado después de value (o last si no se encuentra tal elemento).

Complejidad

Dado N como std:: distance ( first, last ) :

1) Como máximo 2log 2 (N)+O(1) comparaciones con value usando operator < (hasta C++20) std:: less { } (desde C++20) .
2) Como máximo 2log 2 (N)+O(1) aplicaciones del comparador comp .

Sin embargo, si ForwardIt no es un LegacyRandomAccessIterator , el número de incrementos del iterador es lineal en N . Cabe destacar que los iteradores de std::set y std::multiset no son de acceso aleatorio, por lo que sus funciones miembro std::set::equal_range (resp. std::multiset::equal_range ) deberían preferirse.

Notas

Aunque std::equal_range solo requiere que [ first , last ) esté particionado, este algoritmo se utiliza normalmente en el caso donde [ first , last ) está ordenado, de modo que la búsqueda binaria es válida para cualquier value .

Además de los requisitos de std::lower_bound y std::upper_bound , std::equal_range también requiere que operator < o comp sean asimétricos (es decir, a < b y b < a siempre tengan resultados diferentes).

Por lo tanto, los resultados intermedios de la búsqueda binaria pueden ser compartidos por std::lower_bound y std::upper_bound . Por ejemplo, el resultado de la llamada std::lower_bound puede usarse como argumento de first en la llamada std::upper_bound .

Macro de prueba de características Valor Std Característica
__cpp_lib_algorithm_default_value_type 202403 (C++26) Inicialización por lista para algoritmos ( 1,2 )

Implementación posible

equal_range (1)
template<class ForwardIt,
         class T = typename std::iterator_traits<ForwardIt>::value_type>
constexpr std::pair<ForwardIt, ForwardIt> 
    equal_range(ForwardIt first, ForwardIt last, const T& value)
{
    return std::equal_range(first, last, value, std::less{});
}
equal_range (2)
template<class ForwardIt,
         class T = typename std::iterator_traits<ForwardIt>::value_type,
         class Compare>
constexpr 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));
}

Ejemplo

#include <algorithm>
#include <complex>
#include <iostream>
#include <vector>
struct S
{
    int number;
    char name;
    // nota: name es ignorado por este operador de comparación
    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()
{
    // nota: no está ordenado, solo particionado respecto a S definido abajo
    const std::vector<S> vec{{1, 'A'}, {2, 'B'}, {2, 'C'},
                             {2, 'D'}, {4, 'G'}, {3, 'F'}};
    const S value{2, '?'};
    std::cout << "Comparar usando S::operator<(): ";
    const auto p = std::equal_range(vec.begin(), vec.end(), value);
    for (auto it = p.first; it != p.second; ++it)
        std::cout << it->name << ' ';
    std::cout << '\n';
    std::cout << "Usando comparación heterogénea: ";
    const auto p2 = std::equal_range(vec.begin(), vec.end(), 2, Comp{});
    for (auto it = p2.first; it != p2.second; ++it)
        std::cout << it->name << ' ';
    std::cout << '\n';
    using CD = std::complex<double>;
    std::vector<CD> nums{{1, 0}, {2, 2}, {2, 1}, {3, 0}, {3, 1}};
    auto cmpz = [](CD x, CD y) { return x.real() < y.real(); };
    #ifdef __cpp_lib_algorithm_default_value_type
        auto p3 = std::equal_range(nums.cbegin(), nums.cend(), {2, 0}, cmpz);
    #else
        auto p3 = std::equal_range(nums.cbegin(), nums.cend(), CD{2, 0}, cmpz);
    #endif
    for (auto it = p3.first; it != p3.second; ++it)
        std::cout << *it << ' ';
    std::cout << '\n';
}

Salida:

Comparar usando S::operator<(): B C D 
Usando comparación heterogénea: B C D
(2,2) (2, 1)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 270 C++98 Compare se requería que cumpliera con Compare y T se requería
que fuera LessThanComparable (se requería ordenamiento débil estricto)
solo se requiere una partición;
se permiten comparaciones heterogéneas
LWG 384 C++98 como máximo 2log 2 (N)+1 comparaciones
estaban permitidas, lo cual no es implementable [1]
corregido a 2log 2 (N)+O(1)
  1. Aplicar equal_range a un rango de un solo elemento requiere 2 comparaciones, pero como máximo se permite 1 comparación según el requisito de complejidad.

Véase también

devuelve un iterador al primer elemento no menor que el valor dado
(plantilla de función)
devuelve un iterador al primer elemento mayor que cierto valor
(plantilla de función)
determina si un elemento existe en un rango parcialmente ordenado
(plantilla de función)
divide un rango de elementos en dos grupos
(plantilla de función)
determina si dos conjuntos de elementos son iguales
(plantilla de función)
devuelve el rango de elementos que coinciden con una clave específica
(función miembro pública de std::set<Key,Compare,Allocator> )
devuelve el rango de elementos que coinciden con una clave específica
(función miembro pública de std::multiset<Key,Compare,Allocator> )
devuelve el rango de elementos que coinciden con una clave específica
(objeto función de algoritmo)