2012-04-03 14 views
26

C'è una funzione in che utilizza la ricerca binaria, come lower_bound ma che restituisce l'elemento ultimameno-che-o-uguale-a in base a un determinato predicato?<algorithm> funzione per la ricerca di ultimo elemento di meno-che-o-uguale, come lower_bound

lower_bound è definito da:

trova la posizione del primo elemento in un intervallo ordinata che ha un valore superiore o equivalente a un valore specificato, dove può essere specificato il criterio d'ordine da un predicato binario.

e upper_bound:

trova la posizione del primo elemento in un intervallo ordinata che ha un valore che è superiore un valore specificato, in cui il criterio di ordinamento può essere specificato da un predicato binario.

In particolare, ho un contenitore di eventi ordinati nel tempo e per un determinato periodo di tempo voglio trovare l'ultimo elemento che è venuto prima o in quel punto. Posso ottenere questo risultato con una combinazione di limiti superiori/inferiori, iteratori inversi e utilizzando std::greater o std::greater_equal?

EDIT: un tweak era necessario per il suggerimento di user763305 per far fronte a se chiedete un punto prima dell'inizio della matrice:

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 un avvertimento sull'utilizzo di un comparatore diverso - si * deve * usare lo stesso comparatore (o uno logicamente equivalente) a quello con cui è stato ordinato l'intervallo, altrimenti gli algoritmi di ricerca binaria hanno un comportamento indefinito. Quindi se si volesse usare 'std :: greater' si dovrebbe invertire la gamma o usare un iteratore inverso su di esso. E non puoi mai usare 'std :: greater_equal' come comparatore perché non è un ordine debole. –

risposta

33

In un contenitore ordinato, l'ultimo elemento che è inferiore o equivalente a x, l'elemento prima del primo elemento è maggiore di x.

In tal modo è possibile chiamare std::upper_bound e decrementare l'iteratore restituito una volta. (Prima decremento, è necessario, naturalmente, controllare che non sia l'iteratore cominciare, se lo è, allora non ci sono elementi che sono inferiori o pari a x.)

+1

Grazie - Avrei dovuto dire che questo è simile a quello che ho già, anche se ho usato lower_bound il che significa che ho dovuto eseguire più controlli. L'utilizzo di upper_bound lo semplifica alquanto.Speravo però che un incantesimo come 'lower_bound (rbegin(), rend(), value, std :: greater())' avrebbe fatto ciò di cui avevo bisogno in una volta –

+1

@the_mandrill: Penso che funzioni, ma restituisce un iteratore inverso, che presumibilmente dovresti convertire in un normale iteratore. Personalmente trovo che tali conversioni più confuse di decrementare un iteratore sarebbero :-) –

+0

Hmm, ho appena scoperto che questo non è abbastanza perché fallisce nel caso in cui si stia cercando un punto prima dell'inizio dell'array. Ho aggiunto la soluzione alla domanda –

6

Ecco una funzione wrapper superiore limite che restituisce il numero più grande di un contenitore o una matrice che è inferiore o uguale a un determinato valore:

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; 
} 

per una migliore spiegazione di ciò che questo sta facendo e come utilizzare questa funzione, controlla:

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