Espacios de nombres
Variantes

std::ranges::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
 
Algoritmos restringidos
Operaciones de secuencia no modificantes
Operaciones de secuencia modificantes
Operaciones en almacenamiento sin inicializar
Operaciones de partición
Operaciones de ordenamiento
Operaciones de búsqueda binaria
Operaciones de conjuntos (en rangos ordenados)
Operaciones de montículo/montón
Operaciones de mínimo/máximo
Permutaciones
 
<tbody> </tbody> <tbody class="t-dcl-rev t-dcl-rev-num "> </tbody><tbody> </tbody> <tbody class="t-dcl-rev t-dcl-rev-num "> </tbody><tbody> </tbody>
Definido en el archivo de encabezado <algorithm>
Signatura de la llamada
(1)
template< std::forward_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity, std::indirect_strict_weak_order <const T*, std::projected<I, Proj>> Comp = ranges::less > constexpr ranges::subrange<I> equal_range( I first, S last, const T& value, Comp comp = {}, Proj proj = {} );
(desde C++20)
(hasta C++26)
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, class T = std::projected_value_t<I, Proj>, std::indirect_strict_weak_order <const T*, std::projected<I, Proj>> Comp = ranges::less > constexpr ranges::subrange<I> equal_range( I first, S last, const T& value, Comp comp = {}, Proj proj = {} );
(desde C++26)
(2)
template< ranges::forward_range R, class T, class Proj = std::identity, std::indirect_strict_weak_order <const T*, std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less > constexpr ranges::borrowed_subrange_t<R> equal_range( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
(desde C++20)
(hasta C++26)
template< ranges::forward_range R, class Proj = std::identity, class T = std::projected_value_t<ranges::iterator_t<R>, Proj>, std::indirect_strict_weak_order <const T*, std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less > constexpr ranges::borrowed_subrange_t<R> equal_range( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
(desde C++26)

El rango [firstlast) debe estar al menos parcialmente ordenado con respecto a value, es decir, debe satisfacer todos los siguientes requisitos:

  • particionado con respecto a element < value o comp(element, value) (es decir, todos los elementos para los que la expresión es true preceden a todos los elementos para los que la expresión es false).
  • particionado con respecto a !(value < element) o !comp(value, element).
  • para todos los elementos, si element < value o comp(element, value) es true entonces !(value < element) o !comp(value, element) también es true.

Un rango completamente ordenado cumple con estos criterios.

La vista devuelta se construye a partir de dos iteradores, uno que apunta al primer elemento que es no menor que value y otro que apunta al primer elemento mayor que value. El primer iterador se puede obtener alternativamente con std::ranges::lower_bound(), el segundo con std::ranges::upper_bound().

2) Igual que (1), pero utiliza r como rango de origen, como si usara el rango ranges::begin(r) como first y ranges::end(r) como last.

Las entidades similares a funciones descritas en esta página son niebloids, es decir:

En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.

Parámetros

first, last - El rango de los elementos a examinar.
r - El rango de los elementos a examinar.
value - El valor con el que comparar los elementos.
comp - Si el primer argumento es menor que (es decir, está ordenado antes) el segundo.
proj - La proyección que se aplicará a los elementos.

Valor de retorno

std::ranges::subrange contiene un par de iteradores que definen el rango deseado, el primero apunta al primer elemento que no es menor que value y el segundo apunta al primer elemento que es mayor que value.

Si no hay elementos que sean menores que value, el último iterador (iterador que sea igual a last o ranges::end(r)) se devuelve como el primer elemento. De manera similar, si no hay elementos que sean mayores que value, el último iterador se devuelve como el segundo elemento.

Complejidad

La cantidad de comparaciones realizadas es logarítmica en la distancia entre first y last (como máximo 2 * log
2
(last - first) + O(1)
comparaciones). Sin embargo, para un iterador que no modela random_access_iterator, la cantidad de incrementos del iterador es lineal.

Posible implementación

struct equal_range_fn
{
    template<std::forward_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity, class T = std::projected_value_t<I, Proj>,
             std::indirect_strict_weak_order
                 <const T*, std::projected<I, Proj>> Comp = ranges::less>
    constexpr ranges::subrange<I>
        operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return ranges::subrange
        (
            ranges::lower_bound(first, last, value, std::ref(comp), std::ref(proj)),
            ranges::upper_bound(first, last, value, std::ref(comp), std::ref(proj))
        );
    }
 
    template<ranges::forward_range R, class Proj = std::identity,
             class T = std::projected_value_t<ranges::iterator_t<R>, Proj>,
             std::indirect_strict_weak_order
                 <const T*, std::projected<ranges::iterator_t<R>,
                                           Proj>> Comp = ranges::less>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r), value,
                       std::ref(comp), std::ref(proj));
    }
};
 
inline constexpr equal_range_fn equal_range;

Notas

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)

Ejemplo

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

struct S
{
    int num {};
    char nombre {};
    // nota: nombre se ignora por estos operadores de comparación
    friend bool operator== (const S s1, const S s2) { return s1.num == s2.num; }
    friend auto operator<=>(const S s1, const S s2) { return s1.num <=> s2.num; }
    friend std::ostream& operator<<(std::ostream& os, S o)
    {
        return os << '{' << o.num << ", '" << o.nombre << "'}";
    }
};

void println(auto comentario, const auto& v)
{
    for (std::cout << comentario; const auto& e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}

int main()
{
    // nota: no ordenado, solo particionado con respecto a S abajo
    std::vector<S> vec
    {
        {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4, 'D'}, {4,'G'}, {3,'F'}
    };
    
    const S valor{2, '?'};
    
    namespace ranges = std::ranges;
    
    auto a = ranges::equal_range(vec, valor);
    println("1. ", a);
    
    auto b = ranges::equal_range(vec.begin(), vec.end(), valor);
    println("2. ", b);
    
    auto c = ranges::equal_range(vec, 'D', ranges::less {}, &S::nombre);
    println("3. ", c);
    
    auto d = ranges::equal_range(vec.begin(), vec.end(), 'D', ranges::less {}, &S::nombre);
    println("4. ", d);

    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 = ranges::equal_range(nums, {2, 0}, cmpz);
    #else
        auto p3 = ranges::equal_range(nums, CD{2, 0}, cmpz);
    #endif
    println("5. ", p3);
}

Salida:

1. {2, 'B'} {2, 'C'} {2, 'D'}
2. {2, 'B'} {2, 'C'} {2, 'D'}
3. {2, 'D'} {4, 'D'}
4. {2, 'D'} {4, 'D'}
5. (2,2) (2,1)

Véase también

Devuelve un iterador al primer elemento no menor que el valor dado.
(niebloid) [editar]
Devuelve un iterador al primer elemento mayor que un cierto valor.
(niebloid) [editar]
Determina si un elemento existe en un cierto rango.
(niebloid) [editar]
Divide un rango de elementos en dos grupos
(niebloid) [editar]
Determina si dos conjuntos de elementos son iguales.
(niebloid) [editar]
Devuelve el rango de los elementos que coinciden con una clave específica.
(plantilla de función) [editar]