Vectores - básico

¿Cómo se puede manejar un vector, básicamente?

#include <iostream>

using namespace std;

int main()
{
int v[] = { 45, 23, 22, 12, 11, 10, -1 };
for(int i = 0; v[ i ] != -1; ++i) {
cout << v[ i ] << endl;
}

return 0;
}


Un posible programa que maneje un vector es éste, publicado ya la semana pasada.

Los vectores son espacios contíguos en memoria, de manera que podemos acceder a sus elementos utilizando el nombre del vector, los corchetes, y la posición.


v[ 0 ] = 11;
cout << v[ 0 ] << endl;


En el programa anterior, se utiliza un centinela para indicar el fin del vector, puesto que en C/C++ (al contrario que en Java) no tenemos de un "miembro" length que nos indique el número de elementos.

De hecho, es bastante típico crear constantes que nos indiquen el número de elementos que contiene un vector:


#include <iostream>

using namespace std;

const int MaxElementos = 6;

int main()
{
    int v[] = { 45, 23, 22, 12, 11, 10 };
    for(int i = 0; i < MaxElementos; ++i) {
        cout << v[ i ] << endl;
    }

    return 0;
}

Vectores de tipos complejos

Finalmente, no es necesario que el tipo del vector (o matriz) sea un tipo básico, como int. También puede ser una estructura. Por ejemplo:


#include <iostream>

using namespace std;

const int MaxDimensiones = 2;

struct Complejo {
    int a;
    int b;
};

void muestra(Complejo v[][MaxDimensiones])
{
    for(int i = 0; i < MaxDimensiones; ++i) {
        for(int j = 0; j < MaxDimensiones; ++j) {
            cout << v[ i ][ j ].a << '+' << v[ i ][ j ].b << 'i' << endl;
        }
    }
}

int main()
{
    Complejo v[MaxDimensiones][MaxDimensiones];

    v[0][0].a = 1; v[0][0].b = 2;
    v[0][1].a = 6; v[0][1].b = 7;
    v[1][0].a = 88; v[1][0].b = 99;
    v[1][1].a = 56; v[1][1].b = 78;

    muestra( v );

    return 0;
}


En este ejemplo se utilizan los números complejos para ilustrar una estructura usada dentro de un vector.

Eficiencia

Para ir practicando con ésto de los vectores que se pueden manejar con punteros, supongamos este programa:


#include <iostream>

using namespace std;

int main()
{
    int v[] = { 45, 23, 22, 12, 11, 10, -1 };
    for(int i = 0; v[ i ] != -1; ++i) {
        cout << v[ i ] << endl;
    }

    return 0;
}


Que, como ya hemos visto, es equivalente a:


#include <iostream>

using namespace std;

int main()
{
    int v[] = { 45, 23, 22, 12, 11, 10, -1 };
    for(int i = 0; *(v + i) != -1; ++i) {
        cout << *(v + i ) << endl;
    }

    return 0;
}


Ese trozo de *(v + i) es lo que se conoce como aritmética de punteros (a un puntero se le puede sumar uno para que llegue a la siguiente posición, lo cuál, en este caso, al ser un vector (contíguo en memoria), es correcto) ...

¿Cómo podríamos hacer que el bucle fuese eficiente, es decir, que se evitase hacer una suma (en este caso, incluso dos) por cada vuelta de bucle?

Pista: recordad que ++i es más eficiente que i += x.

Respuesta
La respuesta es que, en el anterior trozo de código, para cada posición que recorre el bucle, se recalcula la posición del vector sobre la que se va a actuar. Sería mejor hacer avanzar alguna variable que sirviera de cursor, de manera que, ya que el vector utiliza espacio contíguo en memoria, podamos recorrer todas las posiciones de esta manera.

#include <iostream>

using namespace std;

int main()
{
    int v[] = { 45, 23, 22, 12, 11, 10, -1 };
    for(int * i = v; *i != -1; ++i) {
        cout << *i << endl;
    }

    return 0;
}

Esta versión es muchísimo más eficiente, puesto que sólo es necesario incrementar en uno la variable i, que es un puntero que va señalando sucesivamente, por cada vuelta de bucle, el elemento que se va a tratar.