2010-08-31 13 views
39

È possibile iterare un vettore dalla fine all'inizio?Iterazione del vettore C++ dall'inizio alla fine

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

O è che possibile solo con qualcosa di simile:

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

In C++ 11 è possibile utilizzare for-loop basato su intervallo con adattatore di retromarcia, [vedi qui] (http://stackoverflow.com/a/8544956/1505939) –

+0

in teoria, su una macchina a 32 bit, per la seconda soluzione, se la dimensione del vettore è maggiore di 2.147.483.647 + 1, sarà overflow (vector :: size() è senza segno), ma al momento è probabile che non raggiungerai mai quel limite (anche il limite di vettori corrente su macchine a 32 bit è 1.073.741.823). –

risposta

73

Bene, il migliore w ay è:

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

rbegin()/rend() especically progettato a tale scopo. (E sì, incrementando un reverse_interator sposta indietro)

Ora, in teoria, il metodo (utilizzando inizio/fine & --i) avrebbe funzionato, iteratore di vettore di essere bidirezionale, ma ricordate, end() non è l'ultimo elemento - è uno oltre l'ultimo elemento, quindi per prima cosa dovresti decrementare e hai finito quando raggiungi begin() - ma devi ancora eseguire l'elaborazione.

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

} 

AGGIORNAMENTO: Ero apparentemente troppo aggressivo nel riscrivere il ciclo for() in un ciclo while. (La parte importante è il il --i è all'inizio.)

+0

Ho appena realizzato che '--i' causerà un grosso problema se il contenitore è vuoto ... Prima di entrare nel ciclo' do - while 'ha senso controllare '(my_vector.begin()! = My_vector.end()) '. – a1ex07

+1

Perché stai usando un ciclo 'do-while' invece di un ciclo' while'? Quindi non avresti bisogno di alcun controllo speciale per i vettori vuoti. – jamesdlin

7

utente rend()/rbegin() iteratori:

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

2

Usa invertire iteratori e anello da rbegin()-rend()

10

Il "modello" consolidato per reverse-iterazione attraverso campi di chiusura-apertura appare come segue

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

o, se si preferisce,

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

Questo modello è utilizzabile, ad esempio, per la retromarcia-indicizzazione un array utilizzando un indice unsigned

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

(persone non hanno familiarità con questo schema spesso insistono sull'uso firmato tipi interi di matrice indicizzazione specificamente perché credono erroneamente che tipi senza segno impediscono indicizzazione inversa)

Può essere utilizzato per l'iterazione di un array usando un "scorrevole pointer" tecnica

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

oppure può essere utilizzato per reverse-iterazione su un vettore utilizzando un normale (non inversa) iteratore

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

Se si dispone di C++11, è possibile utilizzare auto.

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

uso questo codice

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

Poi:

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

alternativa in C++ 14 basta fare:

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

In C++ 03/11 la maggior parte dei contenitori standard ha anche il metodo .rbegin() e .rend().

Infine, è possibile scrivere l'adattatore gamma backwards come segue:

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

e ora si può fare questo:

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

che credo sia piuttosto bella.

Problemi correlati