2010-08-31 18 views
39

¿Es posible iterar un vector desde el final hasta el comienzo?Iterating C++ vector desde el final hasta el comienzo

for (vector<my_class>::iterator i = my_vector.end(); 
     i != my_vector.begin(); /* ?! */) { 
} 

O es que sólo es posible con algo así:

for (int i = my_vector.size() - 1; i >= 0; --i) { 
} 
+0

En C++ 11 puede usar el bucle for-basado basado en rango con el adaptador inverso, [consulte aquí] (http://stackoverflow.com/a/8544956/1505939) –

+0

teóricamente, en una máquina de 32 bits, para la segunda solución, si el tamaño del vector es más grande que 2.147.483.647 + 1, se desbordará (vector :: tamaño() no está firmado), pero actualmente es probable que nunca llegue a ese límite (también el límite vectorial actual en máquinas de 32 bits es 1.073.741.823) –

Respuesta

73

Bueno, el mejor w ay es:

for (vector<my_class>::reverse_iterator i = my_vector.rbegin(); 
     i != my_vector.rend(); ++i) { 
} 

rbegin()/rend() diseñado específicamente para ese propósito. (Y sí, incrementando un reverse_interator mueve hacia atrás)

Ahora, en teoría, el método (usando iniciar/finalizar & --i) funcionaría, el iterador de vector ser bidireccional, pero recuerda, end() no es el último elemento - es uno más allá del último elemento, por lo que tendrías que disminuir primero, y terminarás cuando llegues a begin() - pero aún tienes que hacer tu procesamiento.

vector<my_class>::iterator i = my_vector.end(); 
while (i != my_vector.begin()) 
{ 
    --i; 
    /*do stuff */) 

} 

ACTUALIZACIÓN: yo era aparentemente demasiado agresivo en re-escribir el bucle for() en un bucle while. (La parte importante es la del --i es al principio.)

+0

Me acabo de dar cuenta de que '--i' causará un gran problema si el contenedor está vacío ... Antes de entrar en el ciclo' do - while' tiene sentido verificar '(my_vector.begin()! = My_vector.end()) '. – a1ex07

+1

¿Por qué está utilizando un bucle 'do-while' en lugar de solo un bucle' while'? Entonces no necesitarías ningún control especial para los vectores vacíos. – jamesdlin

7

usuario rend()/rbegin() iteradores:

for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)

2

Uso revertir iteradores y bucle de rbegin()-rend()

10

El bien establecida "patrón" a tal efecto en los rangos cerrada-abierta la iteración inversa se ve de la siguiente manera

// Iterate over [begin, end) range in reverse 
for (iterator = end; iterator-- != begin;) { 
    // Process `*iterator` 
} 

o, si lo prefiere,

// Iterate over [begin, end) range in reverse 
for (iterator = end; iterator != begin;) { 
    --iterator; 
    // Process `*iterator` 
} 

Este patrón es utilizable, por ejemplo, para una matriz mediante un índice unsigned

int array[N]; 
... 
// Iterate over [0, N) range in reverse 
for (unsigned i = N; i-- != 0;) { 
    array[i]; // <- process it 
} 
indexación inversa 10

(personas no familiarizadas con este patrón a menudo insisten en utilizar firmaron tipos enteros para la indexación de matrices específicamente porque creen erróneamente que los tipos sin signo impiden la indexación inversa)

Se puede utilizar para iterar sobre una matriz mediante un "deslizamiento puntero" técnica

// Iterate over [array, array + N) range in reverse 
for (int *p = array + N; p-- != array;) { 
    *p; // <- process it 
} 

o puede ser utilizado para inversa iteración sobre un vector usando un ordinario (no inversa) iterador

for (vector<my_class>::iterator i = my_vector.end(); i-- != my_vector.begin();) { 
    *i; // <- process it 
} 
19

Si tiene C++11, puede hacer uso de auto.

for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it) 
{ 
} 
-1

uso este código

//print the vector element in reverse order by normal iterator. 
cout <<"print the vector element in reverse order by normal iterator." <<endl; 
vector<string>::iterator iter=vec.end(); 
--iter; 
while (iter != vec.begin()) 
{ 
    cout << *iter << " "; 
    --iter; 
} 
4
template<class It> 
std::reverse_iterator<It> reversed(It it) { 
    return std::reverse_iterator<It>(std::forward<It>(it)); 
} 

Entonces:

for(auto rit = reversed(data.end()); rit != reversed(data.begin()); ++rit) { 
    std::cout << *rit; 

Alternativamente en C++ 14 acaba de hacer:

for(auto rit = std::rbegin(data); rit != std::rend(data); ++rit) { 
    std::cout << *rit; 

En C++ 03/11 contenedores más estándar tienen un método .rbegin() y .rend() también.

Por último, puede escribir el adaptador gama backwards de la siguiente manera:

namespace adl_aux { 
    using std::begin; using std::end; 
    template<class C> 
    decltype(begin(std::declval<C>())) adl_begin(C&& c) { 
    return begin(std::forward<C>(c)); 
    } 
    template<class C> 
    decltype(end(std::declval<C>())) adl_end(C&& c) { 
    return end(std::forward<C>(c)); 
    } 
} 

template<class It> 
struct simple_range { 
    It b_, e_; 
    simple_range():b_(),e_(){} 
    It begin() const { return b_; } 
    It end() const { return e_; } 
    simple_range(It b, It e):b_(b), e_(e) {} 

    template<class OtherRange> 
    simple_range(OtherRange&& o): 
    simple_range(adl_aux::adl_begin(o), adl_aux::adl_end(o)) 
    {} 

    // explicit defaults: 
    simple_range(simple_range const& o) = default; 
    simple_range(simple_range && o) = default; 
    simple_range& operator=(simple_range const& o) = default; 
    simple_range& operator=(simple_range && o) = default; 
}; 
template<class C> 
simple_range< decltype(reversed(adl_aux::adl_begin(std::declval<C&>()))) > 
backwards(C&& c) { 
    return { reversed(adl_aux::adl_end(c)), reversed(adl_aux::adl_begin(c)) }; 
} 

y ahora se puede hacer esto:

for (auto&& x : backwards(ctnr)) 
    std::cout << x; 

que creo que es bastante bonita.

Cuestiones relacionadas