2010-03-07 17 views
61

El objetivo es acceder al elemento "n" de un vector de cadenas en lugar del operador [] o el método "at". Por lo que entiendo, los iteradores pueden usarse para navegar a través de contenedores, pero nunca he usado iteradores antes, y lo que estoy leyendo es confuso.¿Cómo navegar a través de un vector usando iteradores? (C++)

Si alguien pudiera darme alguna información sobre cómo lograr esto, se lo agradecería. Gracias.

+0

no son vectores exclusivos de la STL de C++? Lo editaré sin importar – kevin

+0

@gabe, el título especifica C++. –

+0

kevin: vector es un término genérico que podría ser utilizado por cualquier idioma, en particular los matemáticos relacionados como Mathematica o Matlab. – Gabe

Respuesta

66

Debe utilizar el método begin y end de la clase vector, que devuelve el iterador en referencia al primer y último elemento, respectivamente.

using namespace std; 

vector<string> myvector; // a vector of stings. 


// push some strings in the vector. 
myvector.push_back("a"); 
myvector.push_back("b"); 
myvector.push_back("c"); 
myvector.push_back("d"); 


vector<string>::iterator it; // declare an iterator to a vector of strings 
int n = 3; // nth element to be found. 
int i = 0; // counter. 

// now start at from the beginning 
// and keep iterating over the element till you find 
// nth element...or reach the end of vector. 
for(it = myvector.begin(); it != myvector.end(); it++,i++) { 
    // found nth element..print and break. 
    if(i == n) { 
     cout<< *it << endl; // prints d. 
     break; 
    } 
} 

// other easier ways of doing the same. 
// using operator[] 
cout<<myvector[n]<<endl; // prints d. 

// using the at method 
cout << myvector.at(n) << endl; // prints d. 
+3

Esto omite el hecho de que 'std :: vector' tiene iteradores de acceso aleatorio. – sbi

+15

Independientemente de si sabe que el tipo de iterador es de acceso aleatorio o no, la "mejor" forma de mover un iterador hacia adelante n espacios no es escribir su propio bucle, sino invocar 'std :: advance (it, n)' . Está definido para hacer exactamente lo que usted desea, y automáticamente usará 'it + n' si el iterador está etiquetado como acceso aleatorio, o lo hará si fuera necesario. –

41

Normalmente, los iteradores se usan para acceder a los elementos de un contenedor de forma lineal; sin embargo, con "iteradores de acceso aleatorio", es posible acceder a cualquier elemento de la misma manera que operator[].

Para acceder a los elementos arbitrarios en un vectorvec, se puede utilizar el siguiente:

vec.begin()     // 1st 
vec.begin()+1    // 2nd 
// ... 
vec.begin()+(i-1)   // ith 
// ... 
vec.begin()+(vec.size()-1) // last 

El siguiente es un ejemplo de un patrón acceso típico (versiones anteriores de C++):

int sum = 0; 
using Iter = std::vector<int>::const_iterator; 
for (Iter it = vec.begin(); it!=vec.end(); ++it) { 
    sum += *it; 
} 

La ventaja de utilizar el iterador es que puede aplicar el mismo patrón con otros contenedores:

sum = 0; 
for (Iter it = lst.begin(); it!=lst.end(); ++it) { 
    sum += *it; 
} 

Por esta razón, es muy fácil crear código de la plantilla que trabajará la misma independientemente del tipo de contenedor. Otra ventaja de los iteradores es que no supone que los datos residen en la memoria; por ejemplo, se podría crear un iterador directo que pueda leer datos de un flujo de entrada, o que simplemente genere datos sobre la marcha (por ejemplo, un generador de rango o de números aleatorios).

Otra opción usando std::for_each y lambdas:

sum = 0; 
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; }); 

Como C++ 11 puede utilizar auto de no especificar un nombre de tipo complicado mucho del iterador como se ha visto antes (o incluso más complejo):

sum = 0; 
for (auto it = vec.begin(); it!=vec.end(); ++it) { 
    sum += *it; 
} 

Y, además, no es un simple para cada variante-:

sum = 0; 
for (auto value : vec) { 
    sum += value; 
} 

Y finalmente también está std::accumulate donde debe tener cuidado ya sea que esté agregando números enteros o de punto flotante.

12

Los iteradores de vectores son iteradores de acceso aleatorio, lo que significa que se ven y se sienten como simples punteros.

Puede acceder al enésimo elemento agregando n al iterador devuelto desde el método begin() del contenedor, o puede usar el operador [].

std::vector<int> vec(10); 
std::Vector<int>::iterator it = vec.begin(); 

int sixth = *(it + 5); 
int third = *(2 + it); 
int second = it[1]; 

Alternativamente, puede utilizar la función advance que trabaja con todo tipo de iteradores. (Habría que considerar si usted realmente desea llevar a cabo "de acceso aleatorio" con iteradores no aleatoria de acceso, ya que ello podría ser algo caro hacerlo.)

std::vector<int> vec(10); 
std::vector<int>::iterator it = vec.begin(); 

std::advance(it, 5); 
int sixth = *it; 
+1

Puede usar 'advance' para iteradores de acceso aleatorio también, o iteradores de categoría desconocida, ya que se garantiza que operará en tiempo constante en ese caso. Esta es la razón por la que los iteradores definidos por el usuario deberían estar correctamente etiquetados. –

+0

De hecho, pero 'advance' es realmente molesto de usar (debido al uso de parámetros out) si sabes que estás tratando con iteradores de acceso aleatorio. Solo recomendaría en código genérico, y si no se usa mucho (si el algoritmo no es compatible con iteradores de acceso no aleatorio, que así sea, por ejemplo, 'std :: sort' * podría * ordenar un' std: : list' pero no porque sería ridículamente ineficiente). – UncleBens

+0

Claro, el ejemplo clásico sería si su algoritmo solo realmente * necesita * un InputIterator, pero por alguna razón a veces se salta, por lo que desea que sea más eficiente si el iterador tiene acceso aleatorio. No vale la pena restringir tu algoritmo al acceso aleatorio solo usando 'operator +'. Pero la pregunta era explícitamente sobre vectores, por lo que no hay nada de malo en la primera parte de su respuesta. Simplemente pensé que la segunda parte podría implicar que "no se puede usar el avance con iteradores de acceso aleatorio, incluso si se quiere" para alguien que nunca ha visto 'avanzar' antes. –

Cuestiones relacionadas