next up previous contents
Next: Resumen Up: 7. El TDA Secuencia Previous: 7.1.2 Descripción formal   Contents

7.2 Implementación

La implementación de Secuencia recoge los elementos que vimos en las implementaciones de Arreglo y Conjunto, hay solo tres nuevos elementos de C++: herencia de excepciones, funciones amigas en plantillas y sobrecarga del operador <<, pero antes veamos el código:

/*

secuencia.h

Autor: L. Alejandro Bernal R.

Fecha: 2000.12.03

*/

#ifndef _SECUENCIA_H_

#define _SECUENCIA_H_

#include <stdio.h>

#include <iostream.h>

/*

TDA Secuencia

    Descripción: Una secuencia es un conjunto de elementos del mismo tipo que guardan un orden.

    Invariante: Secuencia=<elem[0],...,elem[n-1]> y (Para todo i,0 <= i < n,elem[i] pertenece a TipoB)

*/

template<class TipoB>

class Secuencia

{

    private:

    // Atributos:

    TipoB *elem; // Elementos de la secuencia.

    int num; // Número de elementos en la secuencia.

    public:

    // Excepciones:

    class Excepcion { }; // Excepcion general.

    class NoHayMemoria : public Excepcion { }; // Excepción: No hay memoria.

    class FueraDeRango : public Excepcion { }; // Excepción: Fuera de rango.

    // Operaciones:

    /*

   Operación Secuencia

       Descripción: Construlle una secuencia vácia.

       Descripción operacional: Secuencia: -> Secuencia

       Precondición: verdadero

       Poscondición: Secuencia=<>

    */

    Secuencia() { num = 0; elem = NULL; }

    /*

    Operación Secuencia

        Descripción: Construlle una secuencia basandose en otra.

        Descripción operacional: Secuencia:  -> Secuencia

        Precondición: otra pertenece a Secuencia

        Poscondición: Secuencia=otra

    */

    Secuencia(Secuencia<TipoB> &otra);

    /*

    Operación Secuencia

        Descripción: Destrulle la secuencia.

        Descripción operacional: Secuencia: ->

        Precondición:

        Poscondición:

    */

    Secuencia() { delete elem; }

    /*

    Operación: =

        Descripción: Asigna (copia) la secuencia fuente.

        Descripcion operacional: =: Secuencia x Secuencia -> Secuencia

        Precondición: fuente pertenece a Secuencia

        Poscondición: secuencia=fuente

    */

    Secuencia<TipoB> &operator = (Secuencia otra);

    /*

    Operación tam

        Descripción: Dice el tamaño de la secuencia.

        Descripción operacional: tam: Secuencia -> N

        Precondición:

        Poscondición: tam=n

    */

    int tam() { return num; }

    /*

    Operación [] 

        Descripción: Selecciona el elemento de la posición i.

        Descripción operacional: []: Secuencia x N -> TipoB

        Precondición: i pertenece a N y 0 <= i < n

        Poscondición: []=elem[i]

    */

    TipoB &operator [](int i);

    /*

    Operación insd 

        Descripción: Inserta después de la posición i.

        Descripción operacional: ins: Secuencia x TipoB -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[i],ele[i+1],...,elem[n-1]> y nuevo pertenece a TipoB y -1 <= i <= n

        Poscondición: secuencia=<elem[0],elem[i],nuevo,elem[i+1],...,elem[n-1]>

    */

    void ins(TipoB nuevo, int i);

    /*

    Operación add

        Descripción: Adiciona un nuevo elemento al final del la secuencia.

        Descripción operacional: add: Secuencia x TipoB -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[n-1]> y nuevo pertenece a TipoB

        Poscondición: secuencia=<elem[0],...,elem[n-1],nuevo>

    */

    void add(TipoB nuevo) { ins(nuevo, num - 1); }

    /*

    Operación eliminar

        Descripción: Elimina el elemento de la posición i.

        Descripción operacional: eliminar: Secuencia x N -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[i-1],elem[1],elem[i+1],...,elem[n-1]> y 0 <= i < n

        Poscondición: secuencia=<elem[0],...,elem[i-1],elem[i+1],\cdots ,elem[n-1]>

    */

    void eliminar(int i);

    /*

    Operación donde

        Descripción: Retorna la posición del elemento en la secuencia. Si no está retorna -1.

        Descripción operacional: donde: Secuencia x TipoB -> N

        Precondición: el pertenece a TipoB

        Poscondición: (Existe un i,elem[i]=el) => donde=i ó (Para todo i,elem[i] != el) => donde=-1

    */

    int donde(TipoB el);

    /*

    Operación +

        Descripción: Une dos secuencias en una tercera, en ésta aparecen primero los elementos de la secuencia inicial y segundos los de la otra secuencia.

        Descripción operacional: +: Secuencia x Secuencia -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[n-1]> y otra=<el[0],...,el[m-1]>

        Poscondición: +=<elem[0],...,elem[n-1],el[0],...,el[m-1]>

    */

    Secuencia<TipoB> operator +(Secuencia<TipoB> otra);

    /*

    Operación <<

        Descripción: Imprime la secuencia en un stream.

        Descripción operacional: <<: ostream x Secuencia -> ostream

        Precondición: is pertenece a ostream y sec pertenece a Secuencia

        Poscondición: ostream=<'<',elem[0],  ','  ,...,  ','  ,elem[n-1]>

    */

    template<class TipoB>

    friend ostream &operator << (ostream &is, Secuencia<TipoB> sec);

}; // class Secuencia

// Operaciones:

/*

Operación Secuencia

    Descripción: Construlle una secuencia basandose en otra.

    Descripción operacional: Secuencia: -> Secuencia

    Precondición: otra pertenece a Secuencia

    Poscondición: Secuencia=otra

*/

template<class TipoB>

Secuencia<TipoB>::Secuencia(Secuencia<TipoB> &fuente)

{

    num = fuente.num;

    elem = new TipoB[num];

    // Si no hay memoria

    if(elem == NULL){

        throw NoHayMemoria();

    }

    for(int i = 0; i < num; i++){

        elem[i] = fuente.elem[i];

    }

}

/*

Operación: =

    Descripción: Asigna (copia) la secuencia fuente.

    Descripcion operacional: =: Secuencia x Secuencia -> Secuencia

    Precondición: fuente pertenece a Secuencia

    Poscondición: secuencia=fuente

*/

template<class TipoB>

Secuencia<TipoB> &Secuencia<TipoB>::operator = (Secuencia<TipoB> otra)

{

    delete elem;

    num = otra.num;

    elem = new TipoB[num];

    // Si no hay memoria

    if(elem == NULL){

        throw NoHayMemoria();

    }

    for(int i = 0; i < num; i++){

        elem[i] = otra.elem[i];

    }

}

/*

Operación []

    Descripción: Selecciona el elemento de la posición i.

    Descripción operacional: []: Secuencia x N -> TipoB

    Precondición: i pertenece a N y 0 <= i < n

    Poscondición: []=elem[i]

*/

template<class TipoB>

TipoB &Secuencia<TipoB>::operator [](int i)

{

    if(i < 0 || i >= num){

        throw FueraDeRango();

    }

    return elem[i];

}

/*

Operación ins

    Descripción: Inserta después de la posición i.

    Descripción operacional: ins: Secuencia x TipoB -> Secuencia

    Precondición: secuencia=<elem[0],...,elem[i],ele[i+1],...,elem[n-1]> y nuevo pertenece a TipoB y -1 <= i <= n

    Poscondición: secuencia=<elem[0],elem[i],nuevo,elem[i+1],...,elem[n-1]>

*/

template<class TipoB>

void Secuencia<TipoB>::ins(TipoB nuevo, int i)

{

    // Verificar el rango de i.

    if(i < -1 || i >= num){

        throw FueraDeRango();

    }

    // i >= -1 && i < num

    int j; //Recorre el arreglo temporal.

    // Pedir memoria para un arreglo con una posición adicional.

    TipoB *tmp = new TipoB[num + 1];

    if(tmp == NULL){

        throw NoHayMemoria();

    }

    // Copiar hasta i, incluido.

    for(j = 0; j <= i; j++){

        tmp[j] = elem[j];

    }

   // Copiar el nuevo.

   tmp[j++] = nuevo;

   // Copiar los que faltan.

   for(;j < num + 1; j++){

       tmp[j] = elem[j - 1];

   }

   delete elem;

        elem = tmp;

        num++;

}

/*

Operación eliminar

        Descripción: Elimina el elemento de la posición i.

        Descripción operacional: eliminar: Secuancia x N -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[i-1],elem[1],elem[i+1],...,elem[n-1]> y 0 <= i < n

        Poscondición: secuencia=<elem[0],...,elem[i-1],elem[i+1],\cdots ,elem[n-1]>

*/

template<class TipoB>

void Secuencia<TipoB>::eliminar(int i)

{

        // Verificar el rango de i.

        if(i < 0 || i >= num){

                throw FueraDeRango();

        }

        

        // Pedir menos memoria.

        TipoB *nuevo = new TipoB[num - 1];

        if(nuevo == NULL){

                throw NoHayMemoria();

        }

        

        int j; // Para recorrer el nuevo arreglo.

        

        // Copiar hasta antes de i;

        for(j = 0; j < i; j++){

                nuevo[j] = elem[j];

        }

        

        // Copiar desde después de i.

        for(; j < num - 1; j++){

                nuevo[j] = elem[j + 1];

        }

        

        // Liberar el viejo y actualizarlo con el nuevo.

        delete elem;

        elem = nuevo;

        num-;

}

/*

Operación donde

        Descripción: Retorna la posición del elemento en la secuencia. Si no está retorna -1.

        Descripción operacional: donde: Secuencia x TipoB -> N

        Precondición: el pertenece a TipoB

        Poscondición: (Existe un i,elem[i]=el) => donde=i ó (Para todo  i,elem[i] != el) => donde=-1

*/

template<class TipoB>

int Secuencia<TipoB>::donde(TipoB el)

{

        for(int i = 0; i < num; i++){

                if(elem[i] == el){

                        return i;

                }

        }

        

        return -1;

}

/*

Operación +

        Descripción: Une dos secuencias en una tercera, en ésta aparecen primero los elementos de la secuencia inicial y segundos los de la otra secuencia.

        Descripción operacional: +: Secuencia x Secuencia -> Secuencia

        Precondición: secuencia=<elem[0],...,elem[n-1]> y otra=<el[0],...,el[m-1]>

        Poscondición: +=<elem[0],...,elem[n-1],el[0],...,el[m-1]>

*/

template<class TipoB>

Secuencia<TipoB> Secuencia<TipoB>::operator +(Secuencia<TipoB> otra)

{

        Secuencia nuevo; // Conjunto unión.

        

        for(int i = 0; i < num; i++){

                nuevo.add(elem[i]);

        }

        for(int i = 0; i < otra.num; i++){

                nuevo.add(otra.elem[i]);

        }

        

        return nuevo;

}

/*

Operación <<

        Descripción: Imprime la secuencia en un stream.

        Descripción operacional: <<: ostream x Secuencia -> ostream

        Precondición: is pertenece a ostream y sec pertenece a Secuencia

        Poscondición: ostream=<'<',elem[0],  ','  ,...,  ','  ,elem[n-1]>

*/

template<class TipoB>

ostream &operator << (ostream &os, Secuencia<TipoB> sec)

{

        os << "<";

        for(int i = 0; i < sec.tam(); i++){

                os << sec[i];

                if(i < sec.tam() - 1){

                        os << ',';

                }

        }

        os << ">";

        

        return os;

}

#endif

//------ Fin de secuencia.h

La primera diferencia es en la declaración de la excepciones:

// Excepciones:

class Excepcion { }; // Excepcion general.

class NoHayMemoria : public Excepcion { };

class FueraDeRango : public Excepcion { };

Se ha establecido una jeraquia de herencia, las dos excepciones son clases derivadas de la más general Excepcion. Esto permite que cuando se vaya a atrapar las excepciones, si a un programa no le intereza saber cual excepción en particular ocurrió, simplemente atrapa a Excepcion.

La segun da diferencia está en el operador amigo:

template<class TipoB>

friend ostream &operator << (ostream &is, Secuencia<TipoB> sec);

La sobrecarga de este operador es importante de hacer, por que el permite imprimir la secuencia. Pero el lector habrá notado que antes del encabezado de función se resescirbe la declaración de plantilla, esto es necesario por que una función amiga realmente no hace parte de la clase y por ende de la plantilla. La implementación de este operador es:

template<class TipoB>

ostream &operator << (ostream &os, Secuencia<TipoB> sec)

{

        os << "<";

        for(int i = 0; i < sec.tam(); i++){

                os << sec[i];

                if(i < sec.tam() - 1){

                        os << ',';

                }

        }

        os << ">";

        

        return os;

}

Igual que cualquier otra función global. Ahora presentremos un código en el que se utilza la secuencia:

/*

secuencia_prueba.cpp

Autor: L. Alejandro Bernal R.

Fecha: 2000.12.04

Descripción: Prueba informal de la Secuencia.

*/

#include "secuencia.h"

#include <iostream.h>

int main()

{

    try{

        Secuencia<float> a,b;

        a.add(10.4);

        a.add(100.56);

        a.add(3.4);

        cout << "a=" << a << '\n';

        b.add(100.56);

        b.add(8.7);

        cout << "b=" << b << '\n';

        Secuencia<float> c;

        c = a + b;

        cout << "c=" << c << '\n';

        c.ins(0.0, -1);

        c.ins(1.0, 0);

        c.ins(5.0, 4);

        cout << "c=" << c << '\n';

    }

    catch(Secuencia<float>::Excepcion){

        cerr << "Error: O no hay memoria o esta fuera de rango\n";

        return 2;

    }

    return 0;

}

//-----Fin secuencia_prueba.cpp

Este código no es que sea muy útil pero de una idea general de como usar el TDA Secuencia. Fígese que en la captura de excepciones se atrapa la clase general Excepcion y no las particulares, esto podría servir cuando no importa mucho es especificidad en un programa.


next up previous contents
Next: Resumen Up: 7. El TDA Secuencia Previous: 7.1.2 Descripción formal   Contents
Ing. L. Alejandro Bernal R. 2001-01-18
Free Web Hosting