2012-04-03 10 views
26

¿Hay una función en la que utiliza la búsqueda binaria, como lower_bound pero que devuelve el elemento últimamenos-que-o-igual-a según un predicado dado?<algorithm> función para encontrar último elemento menos-que-o-igual, como límite distinto

lower_bound se define a:

encuentra la posición de la primera elemento en un rango ordenado que tiene un valor mayor que o equivalente a un valor especificado, donde el criterio de ordenación puede ser especificado por un predicado binario.

y upper_bound:

encuentra la posición de la primera elemento en un rango ordenado que tiene un valor que es mayor que un valor especificado, donde el criterio de ordenación puede ser especificado por un predicado binario

Específicamente, tengo un contenedor de eventos ordenados por tiempo y por un tiempo dado quiero encontrar el último elemento que venía antes o en ese momento. ¿Puedo lograrlo con alguna combinación de límite superior/inferior, iteradores inversos y usando std::greater o std::greater_equal?

EDIT: un pellizco se necesitaba para la sugerencia de user763305 para hacer frente a si pide un punto antes del comienzo de la matriz:

iterator it=upper_bound(begin(), end(), val, LessThanFunction()); 
if (it!=begin()) { 
    it--; // not at end of array so rewind to previous item 
} else { 
    it=end(); // no items before this point, so return end() 
} 
return it; 
+1

Solo una advertencia sobre el uso de un comparador diferente - usted * debe * usar el mismo comparador (o uno lógicamente equivalente) al que el rango fue ordenado, de lo contrario los algoritmos de búsqueda binarios tienen un comportamiento indefinido. Entonces, si quisieras usar 'std :: greater' primero tendrías que invertir el rango o usar un iterador inverso sobre él. Y nunca se puede usar 'std :: greater_equal' como un comparador porque no es un orden débil estricto. –

Respuesta

33

En un recipiente ordenada, el último elemento que es menor o equivalente a x, es el elemento antes del primer elemento que es mayor que x.

Así puede llamar al std::upper_bound, y disminuir el iterador devuelto una vez. (Antes de decremento, debe, por supuesto, y comprueba que no está el iterador comenzar, y si lo es, entonces no hay elementos que son inferiores o equivalentes a x.)

+1

Gracias - Debería haber mencionado que esto es similar a lo que ya hice, aunque utilicé lower_bound, lo que significa que tuve que realizar más comprobaciones. Usar upper_bound simplifica esto de alguna manera.Sin embargo, esperaba que un conjuro como 'lower_bound (rbegin(), rend(), value, std :: greater())' hiciera lo que necesitaba de una vez –

+1

@the_mandrill: creo que funciona, pero vuelve un iterador inverso, que presumiblemente deberías convertir a un iterador normal. Personalmente encuentro que tales conversiones son más confusas que la disminución de un iterador :-) –

+0

Hmm, acaba de descubrir que esto no es suficiente porque falla en el caso de que esté buscando un punto antes del inicio de la matriz. He agregado la solución a la pregunta –

6

Aquí es una función de envoltura alrededor de límite superior que devuelve el mayor número en un recipiente o una matriz que es menor o igual a un valor dado:

template <class ForwardIterator, class T> 
    ForwardIterator largest_less_than_or_equal_to (ForwardIterator first, 
                ForwardIterator last, 
                const T& value) 
{ 
    ForwardIterator upperb = upper_bound(first, last, value); 

    // First element is >, so none are <= 
    if(upperb == first) 
    return NULL; 

    // All elements are <=, so return the largest. 
    if(upperb == last) 
    return --upperb; 

    return upperb - 1; 
} 

para una mejor explicación de lo que esto está haciendo y cómo utilizar esta función, echa un vistazo a:

C++ STL — Find last number less than or equal to a given element in an array or container

Cuestiones relacionadas