Espacios de nombres
Variantes

std::equal_range

De cppreference.com
 
 
Biblioteca de algoritmos
Políticas de ejecución (C++17)
Operaciones de secuencia no modificantes
(C++11)(C++11)(C++11)
(C++17)
Operaciones de secuencia modificantes
Operaciones en almacenamiento no inicializado
Operaciones de partición
Operaciones de ordenación
(C++11)
Operaciones de búsqueda binaria
Operaciones de conjuntos (en rangos ordenados)
Operaciones de pila
(C++11)
Operaciones mínimo/máximo
(C++11)
(C++17)
Permutaciones
Operaciones numéricas
Bibliotecas C
 
<tbody> </tbody> <tbody class="t-dcl-rev t-dcl-rev-num "> </tbody><tbody> </tbody> <tbody class="t-dcl-rev t-dcl-rev-num "> </tbody>
Definido en el archivo de 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 [firstlast).

1) La equivalencia se comprueba usando operator<:

Devuelve el resultado de std::lower_bound(first, last, value) y std::upper_bound(first, last, value).

Si se cumple alguna de las siguientes condiciones, el comportamiento no está definido:

  • Para cualquier elemento elem de [firstlast), bool(elem < value) no implica !bool(value < elem).
  • Los elementos elem de [firstlast) 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 comprueba usando comp:
Devuelve el resultado de std::lower_bound(first, last, value, comp) y std::upper_bound(first, last, value, comp).
Si se cumple alguna de las siguientes condiciones, el comportamiento no está definido:
  • Para cualquier elemento elem de [firstlast), bool(comp(elem, value)) no implica !bool(comp(value, elem)).
  • Los elementos elem de [firstlast) no están particionados con respecto a las expresiones bool(comp(elem, value)) y !bool(comp(value, elem)).

Parámetros

first, last - El rango particionado de los elementos a examinar.
value - El valor con el que comparar los elementos.
comp - Predicado binario que devuelve ​true Si el primer argumento está ordenado antes del segundo.

La signatura de la función predicado deberá ser equivalente a la siguiente:

bool pred(const Tipo1 &a, const Tipo2 &b);

Mientras que la signatura no necesita tener const &, la función no debe modificar los objetos que se le han pasado y debe ser capaz de aceptar todos los valores de tipo (posiblemente const) Tipo1 y Tipo2 independientemente de la categoría de valor (por lo tanto, no se permite Tipo1 &, ni Tipo1 a menos que para Tipo1 un movimiento sea equivalente a una copia (desde C++11)).
El tipo Tipo1 debe ser tal que un objeto de tipo T puede convertirse implícitamente a Tipo1. El tipo Tipo2 debe ser tal que un objeto de tipo ForwardIt puede ser desreferenciado y luego convertido implícitamente a Tipo2. ​

Requisitos de tipo
-
ForwardIt debe satisfacer los requisitos de ForwardIterator.
-
Compare debe satisfacer 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 [firstlast) no ordenado antes de value (o last si no se encuentra tal elemento), y
  • second es un iterador al primer elemento del rango [firstlast) ordenado después de value (o last si no se encuentra tal elemento).

Complejidad

Dada 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 de comparador comp.

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

Notas

Aunque std::equal_range solo requiere que [firstlast) esté particionado, este algoritmo se utiliza generalmente en el caso en que [firstlast) esté ordenado, de modo que la búsqueda binaria sea 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 tienen 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 a std::lower_bound se puede utilizar como argumento de first en la llamada a std::upper_bound.


Macro de Prueba de característica Valor Estándar Comentario
__cpp_lib_algorithm_default_value_type 202403 (C++26) Inicialización de lista para algoritmos (1,2)

Posible implementación

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 num;
    char nombre;
    // nota: nombre se ignora por este operador de comparación
    bool operator<(const S& s) const { return num < s.num; }
};

struct Comp
{
    bool operator()(const S& s, int i) const { return s.num < i; }
    bool operator()(int i, const S& s) const { return i < s.num; }
};

int main()
{
    // nota: no ordenado, solo particionado con respecto a S definida 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->nombre << ' ';
    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->nombre << ' ';
    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 de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
LWG 270 C++98 Se requería que Compare satisfaciera Compare y T se requería
que fuera LessThanComparable (se requería un orden débil estricto).
Sólo se requiere una partición;
se permiten comparaciones heterogéneas.
LWG 384 C++98 Como máximo se permitían 2log
2
(N)+1
comparaciones,
, lo cual no es implementable[1]
Se corrigió a 2log
2
(N)+O(1)
.
  1. Aplicando equal_range a un solo elemento del rango requiere dos comparaciones, pero como máximo se admite una comparación por el requisito de complejidad.

Véase también

Devuelve un iterador al primer elemento no menor que el valor dado.
(plantilla de función) [editar]
Devuelve un iterador al primer elemento mayor que un valor determinado.
(plantilla de función) [editar]
Determina si un elemento existe en un rango parcialmente ordenado.
(plantilla de función) [editar]
Divide un rango de elementos en dos grupos.
(plantilla de función) [editar]
Determina si dos conjuntos de elementos son iguales.
(plantilla de función) [editar]
Devuelve un rango de elementos que coinciden con una clase específica.
(función miembro pública de std::set<Key,Compare,Allocator>) [editar]
Devuelve un rango de elementos que coinciden con una clase específica.
(función miembro pública de std::multiset<Key,Compare,Allocator>) [editar]
Devuelve un rango de elementos que coinciden con una clave especifica.
(niebloid) [editar]