2010-08-31 22 views
39

Czy można iterować wektor od końca do początku?Iterowanie wektora C++ od końca do początku

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

Albo jest to możliwe tylko z czymś takim:

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

W C++ 11 można użyć pętli for z adapterem odwrotnym, [patrz tutaj] (http://stackoverflow.com/a/8544956/1505939) –

+0

Teoretycznie na komputerze 32-bitowym, dla drugie rozwiązanie, jeśli rozmiar wektorowy jest większy niż 2 147 483 647 + 1, to będzie przepełniony (wektor :: size() jest niepodpisany), ale obecnie jest szansa, że ​​nigdy nie osiągniesz tego limitu (również obecny limit wektorowy na maszynach 32-bitowych wynosi 1 073 741 823). –

Odpowiedz

73

Cóż, najlepsza w ay jest:

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

rbegin()/rend(), specjalnie zaprojektowane do tego celu. (I tak, zwiększając się reverse_interator przenosi go do tyłu)

Teraz teoretycznie metoda (stosując rozpoczęcia/zakończenia & --i) będzie działać, iterator VECTOR jest dwukierunkowa, jednak pamiętać, że koniec() nie jest ostatnim elementem - to jeden poza ostatnim elementem, więc musisz najpierw zmniejszyć, a skończysz, gdy osiągniesz begin() - ale nadal musisz wykonać przetwarzanie.

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

} 

UPDATE: Byłem najwyraźniej zbyt agresywny w przepisywaniu pętli for() w pętlę while. (Ważną częścią jest The --i jest na początku).

+0

Właśnie zdałem sobie sprawę, że '--i' spowoduje duży problem, jeśli kontener jest pusty ... Zanim przejdziemy do pętli 'do - while', warto sprawdzić' (my_vector.begin()! = My_vector.end()) '. – a1ex07

+1

Dlaczego używasz pętli 'do-while' zamiast tylko pętli' while'? Wtedy nie potrzebujesz specjalnej kontroli dla pustych wektorów. – jamesdlin

7

użytkownika rend()/rbegin() iteratory:

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

2

używać odwrotnego iteratory oraz pętlę z rbegin() do rend()

10

Dobrze ustalony „wzór” dla odwrotnego iteracja zamknięte otwartych przedziałach wygląda następująco

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

albo, jeśli wolisz,

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

wzór ten jest użyteczny, na przykład, do odwrotnego indeksowania tablicy z nieoznaczoną indeks

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

(Osoby znające tego układu często domagać się stosując podpisany typów całkowitych do indeksowania tablicy szczególności ponieważ błędnie sądzić, że bez znaku rodzaje zapobieżenia wstecznego podziału)

może być stosowany dla iteracji przez tablicę używając „ślizgową wskaźnik”technika

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

lub mogą być stosowane do odwrotnej iteracji przez vector przy użyciu zwykłych (nie tyłu) iteracyjnej

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

Jeśli masz C++11, możesz skorzystać z auto.

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

użyć tego kodu

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

Następnie:

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

Alternatywnie w C++ 14 po prostu zrobić:

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

W C++ 03/11 większość standardowych pojemników ma również metodę .rbegin() i .rend().

Wreszcie, można napisać adapter range backwards następująco:

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

a teraz można to zrobić:

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

co moim zdaniem jest całkiem ładna.

Powiązane problemy