Capítulo 9 Vectores

9.1 Definición

Los vectores son arrays de una dimensión.

Aunque C y C++ disponen de estructuras para crear arrays de una dimensión como parte de su sintáxis básica, estas estructuras tienen una limitación importante: que hay que elegir su tamaño en la fase de diseño, no pudiendo variar a lo largo de la ejecución del programa.

Por supuesto, podemos usar una estructura dinámica, reservando memoria y usando un puntero como si se tratase de un array, pero esto también tiene sus limitaciones. Por ejemplo, sigue siendo necesario especificar un tamaño máximo

En otros lenguajes, es posible añadir y eliminar elementos de un array durante la ejecución, sin preocuparse de si hay o no espacio para hacerlo. En C y C++ también, claro, pero es necesario crear TADs específicos para esta tarea.

9.2 Métodos

En las bibliotecas de TDAs, se añaden muchos métodos a los vectores, con el fin de hacerlos lo más genéricos y flexibles posible.

En un vector debemos distinguir entre capacidad y tamaño.

Capacidad es el número máximo de elementos que el vector puede contener en un momento dado.

Medida es el número de elementos que el vector contiene realmente. Este valor será siempre menor o igual que el de capacidad.

Los métodos más básicos e imprescindibles, que implementaremos en nuestros ejemplos, son:

  • Reservar (reserve): Cambia la capacidad (número de elementos) del vector, en general, este valor no puede disminuir durante la ejecución del programa. De modo que el valor suministrado es la capacidad mínima del vector.
  • Redimensionar (resize): Modifica el tamaño o medida del vector.
  • Medida (size): Devuelve el tamaño (número de elementos) actual del vector.
  • Vacio (empty): Devuelve un valor verdadero o distinto de cero si el vector está vacío
  • Capacidad (capacity): Puede haber espacio sin usar, de modo que la capacidad puede ser mayor o igual que el valor de Medida.
  • [] o En (at): Operador de acceso, obtiene una referencia al elemento indicado.
  • Agregar (push_back): Añade un elemento al final del vector.
  • Sustraer (pop_back): Elimina un elemento del final del vector.
  • Primero (front): Obtiene una referencia al primer elemento.
  • Ultimo (back): Obtiene una referencia al último elemento.
  • Insertar (insert): Inserta un elemento en la posición anterior a la dada. El elemento insertado ocupará la posición indicada.
  • Eliminar (erase): Elimina un elemento del vector.
  • Borrar (clear): Elimina todos los elementos.

9.3 Implementación de un vector

Hay muchas formas de implementar vectores, dependiendo de la eficiencia que se pretenda conseguir, ya sea en la velocidad de ejecución o en el manejo de la memoria.

Las operaciones más costosas, en términos de tiempo de ejecución, son las implican cambiar el tamaño de la estructura en memoria: Redimensionar, Ampliar, Reducir, Insertar o Eliminar elementos.

Una condición para que un vector lo sea, la más evidente, es que tiene que almacenarse en un bloque de memoria con direcciones contiguas. Esto nos facilita el acceso a los elementos, ya que es sencillo acceder a uno en particular. Además, estos vectores son compatibles con los tipos estructurados de los que disponemos en C y C++. El problema de esta solución es que nos obliga a reubicar el vector cada vez que sea necesario añadir elementos. Generalmente esto implica reservar un nuevo bloque de memoria, copiar todos los elementos actuales a la nueva ubicación, y borrar el bloque anterior.

Una primera optimización para evitar este inconveniente, al menos en parte, consiste en ampliar y reducir el número de elementos en bloques de memoria con capacidad para varios de ellos. Esto explica porqué tenemos dos métodos con finalidades parecidas: Medida y Capacidad. Si cada vez que nos quedamos sin sitio para añadir nuevos elementos, ampliamos el vector en una cantidad (en principio desconocida), el valor devuelto por Capacidad siempre será mayor o igual al devuelto por Medida.

En la práctica se suele hacer que cada vez que se debe ampliar el vector, se duplica el número de elementos actual. Sin embargo, esto no es más que una de las posibles soluciones, también podríamos añadir un número constante y predefinido de elementos.

Por ejemplo, supongamos que hemos creado un vector para contener 8 enteros:

Array vacío
Array vacío

Si aplicamos el método Medida sobre este vector, el resultado será 0. Si aplicamos el método Capacidad el resultado será 8.

Durante la ejecución del programa vamos añadiendo elementos al vector: 3, 6, 8, 10, 23, 31, 33 y 34; hasta ocupar toda la capacidad del vector:

Array completo
Array completo

Ahora, tanto el método Medida como Capacidad devuelven el mismo valor: 8.

Si intentamos insertar un nuevo valor, 44, antes deberemos ampliar la capacidad del vector. En este caso, duplicamos el número de elementos que podemos almacenar hasta 16, e insertamos el nuevo valor:

Array aumentado
Array aumentado

Ahora, para el método Cuenta obtenemos el valor 9, y para Capacidad 16.

En el diseño del vector deberemos tomar algunas decisiones que afectan a la integridad de la estructura. Por ejemplo, ¿qué debemos hacer si el usuario intenta asignar un valor a un elemento cuyo índice sea mayor que medida y menor que capacidad?

¿Y si el índice indicado es mayor que capacidad?

¿Y si el valor del índice es muy grande?

¿Y si se indica un índice negativo?

Podríamos sencillamente obviar los límites y acceder a esas posiciones sin verificar nada, como pasa con los arrays normales de C y C++. Pero también podemos implementar un funcionamiento más seguro, de modo que los programas no dejen de funcionar en esos casos al intentar modificar posiciones de memoria que no pertenecen a la estructura de datos.

9.4 Descripción de los métodos

Veamos ahora en qué consiste cada uno de los métodos propuestos.

Pero antes, para empezar, necesitamos algunos valores referentes al vector, que debemos mantener actualizados:

  • primero: un puntero al primer elemento del vector.
  • capacidad: capacidad actual del array, número máximo de elementos que puede almacenar.
  • contador: número de elementos usados actualmente.

También responderemos a las preguntas que planteamos anteriormente sobre qué debe hacer nuestro vector cuando se accede a elementos fuera de él.

Aunque pueda parecer tentador, no implementaremos rutinas de seguridad para verificar los márgenes. El motivo es que haciendo eso penalizaríamos la eficiencia de la estructura, y perjudicamos al usuario que tiene cuidado de no sobrepasar los límites del vector, sobre aquellos que son más descuidados.

Reservar

Este método se refiere a la capacidad del vector, es decir, al número máximo de elementos que puede contener.

Como cuando creamos vectores usando tipos agregados, nuestro vector necesitará un valor que indique el número de elementos inicial en la declaración. Cuando encapsulemos el TDA vector en una clase o plantilla esta tarea la realizará el constructor.

Así, si declaramos un vector de 30 elementos, nuestro TDA puede reservar espacio para 30 ó más elementos, y el valor de contador se iniciará a 30. Es decir, podremos acceder al menos a 30 elementos, pero la capacidad podría ser mayor.

Si usamos este método después de la declaración del vector, el valor indicado se interpreta como la nueva capacidad mínima del vector. Si ese valor es menor que la capacidad actual, el método no hace nada. Si es mayor implica una reubicación de la memoria. Se reserva un nuevo bloque suficientemente grande para la nueva capacidad, se copia el contenido del bloque anterior y se libera esa memoria.

Redimensionar

También podemos usar este método durante la ejecución para aumentar o disminuir el tamaño, el número de elementos, del vector.

Si usamos este método podemos distinguir dos casos:

  • El nuevo valor es mayor que el de la capacidad actual: en ese caso la capacidad se aumenta al nuevo valor. Esto implica reservar un bloque de memoria con la nueva capacidad, copiar los elementos desde el bloque anterior, y liberar esa memoria.
  • El nuevo valor es menor que el de la capacidad actual: en ese caso la capacidad se disminuye al valor indicado. Esto también implica una reubicación de la memoria del vector. Si la nueva capacidad es menor que el número de elementos ya almacenados, se conservan los primeros y los sobrantes se pierden.

Medida

Este método es sencillo, sólo debe devolver el valor del contador.

Vacio

También es un método simple, devolverá un valor verdadero o distinto de cero si contador es cero.

Capacidad

Devolverá el valor de capacidad.

[] o En

En una implementación en C usaremos una función En para acceder a la posición indicada, en una implementación C++ sobrecaragaremos el operador [].

Agregar

Añade un elemento al final del vector. Si esta operación implica un cambio de capacidad se producirá una reubicación de los datos.

Sustraer

Elimina un elemento del final del vector

Primero

Obtiene una referencia al primer elemento. Esto sólo en C++. Hay un caso especial, cuando la medida es cero. En ese caso, dado que tenemos que devolver una referencia, tendremos que decidir qué referencia retornar.

Ultimo

Obtiene una referencia al último elemento. Sólo en C++. Como en el caso anterior, también hay un caso especial, cuando la medida es cero. En ese caso también tendremos que decidir qué referencia retornar.

Insertar

Inserta un elemento en la posición anterior a la dada. El elemento insertado ocupará la posición indicada.

Por ejemplo, insertaremos el elemento '32' en la posición 6, es decir, en la que actualmente ocupa el elemento '33':

Insertar elemento
Insertar elemento

Para hacerlo necesitamos desplazar todos los elementos a partir de la posición 6 a la siguiente posición, dejando un hueco para insertar el nuevo:

Elemento insertado
Elemento insertado

Si la inserción de un nuevo elemento implica aumentar la capacidad del vector se producirá una reubicación de los datos.

Eliminar

Elimina un elemento del vector. Se trata de la operación inversa a Insertar.

Borrar

Elimina todos los elementos del vector, dejando la capacidad intacta.

9.5 Inconvenientes sobre tipos estructurados

El principal inconveniente es que la dirección de cualquier elemento del array puede cambiar durante la ejecución del programa.

Con un array normal, la dirección de memoria de un elemento cualquiera se mantiene desde la declaración del array hasta su destrucción. De modo que si conservamos una referencia a un elemento cualquiera usando un puntero, existe una relación unívoca entre ambos.

Con un array del tipo que estamos diseñando, creado mediante clases o plantillas, no podemos asumir que la dirección de un elemento se mantendrá constante a lo largo del programa. A medida que nos quedamos sin espacio para añadir elementos, no sólo redimensionaremos el array, sino que en general, cambiaremos la ubicación en memoria de sus elementos.

De este modo, si mantenemos un puntero a un elemento del array, no podremos estar seguros de que apuntará al mismo elemento después de añadir más valores nuevos durante la ejecución.

9.6 Implementación en C

En este tipo de estructuras no trabajaremos con nodos, como en las anteriores. Todos los datos de un vector se almacenan en direcciones consecutivas de memoria, de modo que sólo necesitamos un bloque de memoria obtenido de forma dinámica.

typedef struct {
    int *datos;
	int capacidad;
	int medida;
} stvector;

Hay una operación especial que realizaremos con frecuencia en nuestros vectores, cada vez que nos quedemos sin espacio o sea necesario modificar la capacidad. Me refiero a la reubicación de la memoria en la que se almacenan los datos.

Esta función debe realizar las siguientes tareas:

  1. Obtener un nuevo bloque de memoria con la nueva capacidad especificada.
  2. Copiar los elementos desde la ubicación anterior a la nueva. Hay que tener en cuenta que si la nueva tiene menor capacidad, sólo se copiarán los elementos que quepan en la nueva ubicación.
  3. Liberar la memoria de la antigua ubicación.
  4. Hacer que la ubicación del vector sea la nueva.

Programa completo en C

/*
 * TDA Vector C
 * Salvador Pozo Coronado
 * Febrero 2013 Con Clase
 */

#include <stdio.h>
#include <stdlib.h>

int min(a,b) {
    return (a<b) ? a : b;
}

/* Declaración de estructura para implementar un vector */
typedef struct {
    int *datos;
	int capacidad;
	int medida;
} stvector;

void Reservar(stvector *v, int nt);

/* Función auxiliar para reubicar los datos a una nueva zona de memoria */
void Reubicar(stvector *v, int nc) {
    int *datos2;
    int i;

    datos2 = (int*)malloc(nc*sizeof(int));
    for(i = 0; i < min(v->capacidad, nc); i++) datos2[i] = v->datos[i];
    if(v->datos) free(v->datos);
    v->datos = datos2;
}

/* Inicia el vector con una capacidad cap */
void Iniciar(stvector *v, int cap) {
    v->datos = NULL;
    v->capacidad = v->medida = 0;
    Reservar(v, cap);
}

/* Libera la memoria asignada al vector */
void Liberar(stvector *v) {
    free(v->datos);
    v->datos = NULL;
    v->capacidad = v->medida = 0;
}

/* Aumenta la capacidad del vector a la nueva capacidad ncap */
void Reservar(stvector *v, int ncap) {
    if(ncap > v->capacidad) Reubicar(v, ncap);
    v->capacidad = ncap;
}

/* Aumenta la capacidad del vector para que pueda almacenar al menos nm elementos */
void Redimensionar(stvector *v, int nm) {
    int cap = v->capacidad;
    while(nm > cap) cap *= 2;
    Reubicar(v, cap);
    v->capacidad = cap;
}

/* Retorna un puntero al elemento n del vector */
int *En(stvector *v, int n) {
    return &(v->datos[n]);
}

/* Retorna un puntero al primer elemento del vector */
int *Vector(stvector *v) {
    return v->datos;
}

/* Añade un elemento de valor d al final del vector */
void Agregar(stvector *v, int d) {
    if(v->medida == v->capacidad) Redimensionar(v, v->medida+1);

    v->datos[v->medida++] = d;
}

/* Elimina el último elemento del vector, y devuelve su valor */
int Sustraer(stvector *v) {
    if(v->medida > 0) return v->datos[--v->medida];
    else return 0;
}

/* Asigna el valor dato a los primeros cuenta elementos del vector */
void Asignar(stvector *v, int cuenta, int dato) {
    int i;
    for(i = 0; i < cuenta; i++) Agregar(v, dato);
}

/* Devuelve el valor del primer elemento del vector */
int Primero(stvector *v) {
    if(v->medida > 0) return v->datos[0];
    else return 0;
}

/* Devuelve el valor del último elemento del vector */
int Ultimo(stvector *v) {
    if(v->medida > 0) return v->datos[v->medida-1];
    else return 0;
}

/* Inserta el valor val en la posición pos del vector */
void Insertar(stvector *v, int pos, int val) {
    int i;

    if(v->medida == v->capacidad) Redimensionar(v, v->medida+1);
    for(i = v->medida; i > pos; i--) v->datos[i] = v->datos[i-1];
    v->datos[pos] = val;
    v->medida++;
}

/* Elimina el valor de la posición pos del vector */
void Eliminar(stvector *v, int pos) {
    int i;

    if(pos < v->medida) {
        for(i = pos; i < v->medida-1; i++) v->datos[i] = v->datos[i+1];
        v->medida--;
    }
}

/* Borra todos los elementos del vector */
void Borrar(stvector *v) {
    v->medida = 0;
}

/* Devuelve el número de elementos del vector */
int Medida(stvector *v) { return v->medida; }
/* Devuelve un valor no nulo si el vector está vacío */
int Vacio(stvector *v) { return !v->medida; }
/* Devuelve la capacidad actual del vector */
int Capacidad(stvector *v) { return v->capacidad; }


int main() {
    stvector v;
    int i;

    Iniciar(&v, 10);
    Asignar(&v, 10, 0);

    for(i = 0; i < 10; i++) Vector(&v)[i] = i;
    for(i = 0; i < 10; i++) Agregar(&v, 100+i);
    Agregar(&v, 23);

    Insertar(&v, 15, 1000);
    Eliminar(&v, 16);
    Eliminar(&v, 108);

    for(i = 0; i < Medida(&v); i++)
        printf("v[%d] = %d\n", i, Vector(&v)[i]);
    *En(&v, 3) = 30;
    printf("v[3] = %d\n", *En(&v, 3));

    printf("Primero = %d\n", Primero(&v));
    printf("Ultimo = %d\n", Ultimo(&v));

    printf("Medida = %d\n", Medida(&v));
    printf("v[ultimo] = %d\n", Sustraer(&v));
    printf("Medida = %d\n", Medida(&v));
    printf("v[ultimo] = %d\n", Sustraer(&v));
    printf("Medida = %d\n", Medida(&v));
    printf("Capacidad = %d\n", Capacidad(&v));
    Liberar(&v);

    return 0;
}

9.7 Implementación en C++

/*
 * TDA Vector C++
 * Salvador Pozo Coronado
 * Febrero 2013 Con Clase
 */

#include <iostream>

using namespace std;

class vector {
    public:
        vector(int m);
        vector(vector& v);
        ~vector();
        void Reservar(int ncap);
        void Redimensionar(int nm);
        int &operator[](int n);
        void Agregar(int d);
        int Sustraer();
        void Asignar(int cuenta, int dato);
        int &Primero();
        int &Ultimo();
        void Insertar(int pos, int val);
        void Eliminar(int pos);
        /* Borra todos los elementos del vector */
        void Borrar() { medida = 0; }
        /* Devuelve el número de elementos del vector */
        int Medida() { return medida; }
        /* Devuelve un valor true si el vector está vacío */
        bool Vacio() { return !medida; }
        /* Devuelve la capacidad actual del vector */
        int Capacidad() { return capacidad; }

    private:
        void Reubicar(int ncap);

        int *datos;
        int medida;
        int capacidad;
};

/* Inicia el vector con una capacidad cap */
vector::vector(int cap) : medida(0), capacidad(cap) {
    datos = new int[cap];
}

/* Constructor copia */
vector::vector(vector& v) : medida(v.medida), capacidad(v.capacidad) {
    datos = new int[v.capacidad];
    for(int i = 0; i < medida; i++)
        datos[i] = v.datos[i];
}

vector::~vector() {
    delete[] datos;
}

void vector::Reubicar(int ncap) {
    int *datos2;
    int i;

    datos2 = new int[ncap];
    for(i = 0; i < min(capacidad, ncap); i++) datos2[i] = datos[i];
    if(datos) delete[] datos;
    datos = datos2;
}

/* Aumenta la capacidad del vector a la nueva capacidad ncap */
void vector::Reservar(int ncap) {
    if(ncap > capacidad) Reubicar(ncap);
    capacidad = ncap;
}

/* Aumenta la capacidad del vector para que pueda almacenar al menos nm elementos */
void vector::Redimensionar(int nm) {
    int cap = capacidad;
    while(nm > cap) cap *= 2;
    Reubicar(cap);
    capacidad = cap;
}

/* Retorna un puntero al elemento n del vector */
int &vector::operator[](int n) {
    return datos[n];
}

/* Añade un elemento de valor d al final del vector */
void vector::Agregar(int d) {
    if(medida == capacidad) Redimensionar(medida+1);

    datos[medida++] = d;
}

/* Elimina el último elemento del vector, y devuelve su valor */
int vector::Sustraer() {
    if(medida > 0) return datos[--medida];
    else return 0;
}

/* Asigna el valor dato a los primeros cuenta elementos del vector */
void vector::Asignar(int cuenta, int dato) {
    for(int i = 0; i < cuenta; i++) Agregar(dato);
}

/* Devuelve el valor del primer elemento del vector */
int &vector::Primero() {
    if(medida > 0) return datos[0];
    else return datos[0];
}

/* Devuelve el valor del último elemento del vector */
int &vector::Ultimo() {
    if(medida > 0) return datos[medida-1];
    else return datos[0];
}

/* Inserta el valor val en la posición pos del vector */
void vector::Insertar(int pos, int val) {
    if(medida == capacidad) Redimensionar(medida+1);
    for(int i = medida; i > pos; i--) datos[i] = datos[i-1];
    datos[pos] = val;
    medida++;
}

/* Elimina el valor de la posición pos del vector */
void vector::Eliminar(int pos) {
    if(pos < medida) {
        for(int i = pos; i < medida-1; i++) datos[i] = datos[i+1];
        medida--;
    }
}

int main() {
    vector v(10);
    int i;

    v.Asignar(10, 0);

    for(i = 0; i < 10; i++) v[i] = i;
    for(i = 0; i < 10; i++) v.Agregar(100+i);
    vector v2(v);

    v.Agregar(23);

    v.Insertar(15, 1000);
    v.Eliminar(16);
    v.Eliminar(108);

    for(i = 0; i < v.Medida(); i++)
        cout << "v[" << i << "] = " << v[i] << endl;
    v[3] = 30;
    cout << "v[3] = " << v[3] << endl;

    cout << "Primero = " << v.Primero() << endl;
    cout << "Ultimo = " << v.Ultimo() << endl;

    cout << "v[ultimo] = " << v.Sustraer() << endl;
    cout << "v[ultimo] = " << v.Sustraer() << endl;

    for(i = 0; i < v2.Medida(); i++)
        cout << "v2[" << i << "] = " << v2[i] << endl;

    return 0;

}

9.8 Implementación en C++ con plantillas

/*
 * TDA Vector C++ con Plantillas
 * Salvador Pozo Coronado
 * Febrero 2013 Con Clase
 */
#include <iostream>
#include "CCadena.h"

using namespace std;

template<class TIPO> class vector {
    public:
        vector(int m);
        vector(vector& v);
        ~vector();
        void Reservar(int ncap);
        void Redimensionar(int nm);
        TIPO &operator[](int n);
        void Agregar(TIPO dato);
        TIPO Sustraer();
        void Asignar(int cuenta, TIPO dato);
        TIPO &Primero();
        TIPO &Ultimo();
        void Insertar(int pos, TIPO val);
        void Eliminar(int pos);
        /* Borra todos los elementos del vector */
        void Borrar() { medida = 0; }
        /* Devuelve el número de elementos del vector */
        int Medida() { return medida; }
        /* Devuelve un valor true si el vector está vacío */
        bool Vacio() { return !medida; }
        /* Devuelve la capacidad actual del vector */
        int Capacidad() { return capacidad; }

    private:
        void Reubicar(int ncap);

        TIPO *datos;
        int medida;
        int capacidad;
};

/* Inicia el vector con una capacidad cap */
template<class TIPO>
vector<TIPO>::vector(int cap) : medida(0), capacidad(cap) {
    datos = new TIPO[cap];
}

/* Constructor copia */
template<class TIPO>
vector<TIPO>::vector(vector& v) : medida(v.medida), capacidad(v.capacidad) {
    datos = new TIPO[v.capacidad];
    for(int i = 0; i < medida; i++)
        datos[i] = v.datos[i];
}

template<class TIPO>
vector<TIPO>::~vector() {
    delete[] datos;
}

template<class TIPO>
void vector<TIPO>::Reubicar(int ncap) {
    TIPO *datos2;
    int i;

    datos2 = new TIPO[ncap];
    for(i = 0; i < min(capacidad, ncap); i++) datos2[i] = datos[i];
    if(datos) delete[] datos;
    datos = datos2;
}

/* Aumenta la capacidad del vector a la nueva capacidad ncap */
template<class TIPO>
void vector<TIPO>::Reservar(int ncap) {
    if(ncap > capacidad) Reubicar(ncap);
    capacidad = ncap;
}

/* Aumenta la capacidad del vector para que pueda almacenar al menos nm elementos */
template<class TIPO>
void vector<TIPO>::Redimensionar(int nm) {
    int cap = capacidad;
    while(nm > cap) cap *= 2;
    Reubicar(cap);
    capacidad = cap;
}

/* Retorna un puntero al elemento n del vector */
template<class TIPO>
TIPO &vector<TIPO>::operator[](int n) {
    return datos[n];
}

/* Añade un elemento de valor d al final del vector */
template<class TIPO>
void vector<TIPO>::Agregar(TIPO d) {
    if(medida == capacidad) Redimensionar(medida+1);

    datos[medida++] = d;
}

/* Elimina el último elemento del vector, y devuelve su valor */
template<class TIPO>
TIPO vector<TIPO>::Sustraer() {
    if(medida > 0) return datos[--medida];
    else return 0;
}

/* Asigna el valor dato a los primeros cuenta elementos del vector */
template<class TIPO>
void vector<TIPO>::Asignar(int cuenta, TIPO dato) {
    for(int i = 0; i < cuenta; i++) Agregar(dato);
}

/* Devuelve el valor del primer elemento del vector */
template<class TIPO>
TIPO &vector<TIPO>::Primero() {
    if(medida > 0) return datos[0];
    else return datos[0];
}

/* Devuelve el valor del último elemento del vector */
template<class TIPO>
TIPO &vector<TIPO>::Ultimo() {
    if(medida > 0) return datos[medida-1];
    else return datos[0];
}

/* Inserta el valor val en la posición pos del vector */
template<class TIPO>
void vector<TIPO>::Insertar(int pos, TIPO val) {
    if(medida == capacidad) Redimensionar(medida+1);
    for(int i = medida; i > pos; i--) datos[i] = datos[i-1];
    datos[pos] = val;
    medida++;
}

/* Elimina el valor de la posición pos del vector */
template<class TIPO>
void vector<TIPO>::Eliminar(int pos) {
    if(pos < medida) {
        for(int i = pos; i < medida-1; i++) datos[i] = datos[i+1];
        medida--;
    }
}

int main() {
    vector<int> v(10);
    int i;

    v.Asignar(10, 0);

    for(i = 0; i < 10; i++) v[i] = i;
    for(i = 0; i < 10; i++) v.Agregar(100+i);
    vector<int> v2(v);
    v.Agregar(23);

    v.Insertar(15, 1000);
    v.Eliminar(16);
    v.Eliminar(108);

    for(i = 0; i < v.Medida(); i++)
        cout << "v[" << i << "] = " << v[i] << endl;
    v[3] = 30;
    cout << "v[3] = " << v[3] << endl;

    cout << "Primero = " << v.Primero() << endl;
    cout << "Ultimo = " << v.Ultimo() << endl;

    cout << "v[ultimo] = " << v.Sustraer() << endl;
    cout << "v[ultimo] = " << v.Sustraer() << endl;


    for(i = 0; i < v2.Medida(); i++)
        cout << "v2[" << i << "] = " << v2[i] << endl;

    vector<Cadena> vc(10);
    vc.Agregar("primero");
    vc.Agregar("segundo");
    vc.Agregar("tercero");
    vc.Agregar("cuarto");
    vc.Agregar("quinto");
    vc.Agregar("sexto");

    for(i = 0; i < vc.Medida(); i++)
        cout << "vc[" << i << "] = " << vc[i] << endl;

    return 0;
}