43
PLANTILLAS Plantillas en C++ Las plantillas nos permiten especificar, con un solo segmento de código, un rango completo de funciones relacionadas (sobrecargadas), llamadas funciones de plantilla, o un rango completo de clases relacionadas, llamadas clases de plantilla. Podríamos escribir una sola plantilla de función para una función de ordenamiento de arreglos y luego hacer que C++ generara automáticamente funciones de plantilla separadas que ordenaran un arreglo de int, un arreglo de float, un arreglo de string, etc. Podríamos escribir una sola plantilla de clase de pila y luego hacer que C++ generara automáticamente clases de plantillas separadas, tales como una clase de pila de int, una clase de pila de float, una clase de pila de string, etc. Hay que observar la diferencia entre las plantillas de función y las funciones de plantilla: las plantillas de función y las plantillas de clase son como plantillas con las cuales trazamos formas, y las funciones de plantilla y las clases de plantilla son como los trazos separados, que tienen la misma forma pero pueden trazarse en colores diferentes, por ejemplo. Plantillas de función Las funciones sobrecargadas se utilizan normalmente para realizar operaciones similares sobre diferentes tipos de datos. Si las operaciones son idénticas para cada tipo, esto puede realizarse en forma más compacta y conveniente mediante el uso de plantillas de función. Basándose en los tipos de argumento que se proporcionan en las llamadas a esa función, el compilador genera automáticamente funciones de código

Plantillas c++

Embed Size (px)

Citation preview

Page 1: Plantillas c++

PLANTILLASPlantillas en C++

Las plantillas nos permiten especificar, con un solo segmento de código, un rango completo de funciones relacionadas (sobrecargadas), llamadas funciones de plantilla, o un rango completo de clases relacionadas, llamadas clases de plantilla.

Podríamos escribir una sola plantilla de función para una función de ordenamiento de arreglos y luego hacer que C++ generara automáticamente funciones de plantilla separadas que ordenaran un arreglo de int, un arreglo de float, un arreglo de string, etc.

Podríamos escribir una sola plantilla de clase de pila y luego hacer que C++ generara automáticamente clases de plantillas separadas, tales como una clase de pila de int, una clase de pila de float, una clase de pila de string, etc.

Hay que observar la diferencia entre las plantillas de función y las funciones de plantilla: las plantillas de función y las plantillas de clase son como plantillas con las cuales trazamos formas, y las funciones de plantilla y las clases de plantilla son como los trazos separados, que tienen la misma forma pero pueden trazarse en colores diferentes, por ejemplo.

Plantillas de función

Las funciones sobrecargadas se utilizan normalmente para realizar operaciones similares sobre diferentes tipos de datos. Si las operaciones son idénticas para cada tipo, esto puede realizarse en forma más compacta y conveniente mediante el uso de plantillas de función. Basándose en los tipos de argumento que se proporcionan en las llamadas a esa función, el compilador genera automáticamente funciones de código objeto separadas para manejar adecuadamente cada tipo de llamada. En C esta tarea se puede realizar mediante macros creadas con la directiva de preprocesador #define.

Sin embargo las macros presentan la posibilidad de serios efectos secundarios y no permiten que el compilador realice revisión de tipo. Las plantillas de función proporcionan una solución compacta similar a la de las macros, pero permiten una revisión de tipo completa. Todas las definiciones de plantillas de función comienzan con la palabra clave témplate, seguida de una lista de parámetros formales para dicha plantilla encerrados entre paréntesis angulares (< y >), cada parámetro formal que representa un tipo debe estar precedido por la palabra clave class, como en:

template <class T>template <class Element Type>template <class BorderType, class FillType> 

Page 2: Plantillas c++

Los parámetros formales de una definición de plantilla se utilizan (como sucedería con los argumentos de tipos integrados o de tipos definidos por el usuario) para especificar los tipos de argumentos de la función, para especificar el tipo de devolución de la función y para declarar variables en el interior de la función.

Para definir una plantillas de clase, se puede usar el siguiente formato:

Primer programa

El siguiente programa hace uso de plantillas para determinar el mínimo y máximo valor de un arreglo de elementos dado.La primera función recibe tiene como parámetros un puntero al tipo de elemento dado y el número de elementos y retorna el menor de los elementos que se encuentran en el arreglo.La segunda función recibe los mismos parámetros y retorna el mayor de los elementos presentes en el arreglo.Finalmente en la función main, se hace una prueba de estas funciones, con arreglos de enteros y flotantes.

template <class T>class Nombre { . . .uso del parámetro T en funciones o datos miembro.. } 

Page 3: Plantillas c++

#include <iostream.h> #include <conio.h>

template <class T>T minimo (T * Array, int num_elemen) {    T min= Array [0] ;

   for (int i=1; i< num_elemen; i++)        if( Array[ i ] < min)             min = Array [ i ];

   return min; } ;

template <class T>T maximo (T * Array, int num_elemen) {   T max= Array [0];

   for (int i=1; i< num_elemen; i++)        if( Array[ i ] > max)             max = Array [ i ];

   return max; };

void main(void){    int ArrayInt [3] = { 2, 8, 6};    float ArrayFloat [3] = { 12.1, 8.7, 5.6 };    int i;      cout<<"Arreglo de enteros: ";   for (i=0; i<3; i++)          cout << ArrayInt[ i ] << " "; 

   cout << endl << "Numero minimo: " << minimo (ArrayInt, 3) << endl         <<"Numero maximo: " << maximo (ArrayInt, 3) << endl << endl;

   cout << "Arreglo de flotantes: ";   for (i=0; i<3; i++)         cout << ArrayFloat[ i ] << " ";         cout << endl <<"Numero minimo: " << minimo (ArrayFloat, 3) << endl               <<"Numero maximo: " << maximo (ArrayFloat, 3);

   getch(); } 

Page 4: Plantillas c++

Segundo programa

En este programa se hace uso de plantillas, para elaborar una función que permita ordenar los elementos de un arreglo.Esta función recibe tiene como parámetros, un puntero al tipo de elemento dado, y dos enteros que indican los índices del primero y último elemento.Aquí se hace uso del algoritmo OrdenarShell para llevar a cabo la tarea. En la función principal se prueba esta plantilla con arreglos de enteros y flotantes.

Page 5: Plantillas c++

#include <iostream.h>#include <conio.h>

template <class T>void Ordenar ( T * a, int st, int fn) {   int i, j , k;   T item_a_ordenar;

   k = 1 ;

   do    {       k= 3 * k + 1;     } while (k < fn - st + 1) ;

   do    {       k /= 3 ;

       for (i= st+k; i<=fn; i++)        {              item_a_ordenar = a [ i ] ;              j = i ;

            while (item_a_ordenar < a [ j-k])             {                a [ j] =a [ j-k] ;                j -=k;

               if(j < st+k)                  break;             }

            a [j]=item_a_ordenar;         }    } while(k > 1); }

void main(void){     int Arraylnt[3] = { 2, 3, 1 } ;    float ArrayFloat[3] = {25.0, 3.0, 45.2 } ;    int i ;

    cout << "Enteros: " << endl          << "Arreglo original: ";

    for (i=0; i<3; i++)           cout << Arraylnt[ i ] << " ";

    Ordenar(Arraylnt, 0, 2);     cout << endl << "Luego de ordenar: ";

    for (i=0; i<3; i++)           cout << Arraylnt[ i ] << " ";

    cout << endl << endl           << "Flotantes: " << endl           << "Arreglo original: "; 

Page 6: Plantillas c++

Tercer programa

En este programa se implementa, mediante el uso de plantillas la clase NuevaPila, que consiste en una Pila, en la que se pueden llevar a cabo las operaciones como insertar y eliminar datos de la misma, mostrar en pantalla los datos de la pila.

Esta es una pila estática, con un número predefinido de 10 elementos.En al función principal, se usa una pila de enteros, flotantes ycaracteres para poder llevar a cabo una prueba de la plantilla creada.

#include <iostream.h>#include <conio.h>

template <class T>void Ordenar ( T * a, int st, int fn) {   int i, j , k;   T item_a_ordenar;

   k = 1 ;

   do    {       k= 3 * k + 1;     } while (k < fn - st + 1) ;

   do    {       k /= 3 ;

       for (i= st+k; i<=fn; i++)        {              item_a_ordenar = a [ i ] ;              j = i ;

            while (item_a_ordenar < a [ j-k])             {                a [ j] =a [ j-k] ;                j -=k;

               if(j < st+k)                  break;             }

            a [j]=item_a_ordenar;         }    } while(k > 1); }

void main(void){     int Arraylnt[3] = { 2, 3, 1 } ;    float ArrayFloat[3] = {25.0, 3.0, 45.2 } ;    int i ;

    cout << "Enteros: " << endl          << "Arreglo original: ";

    for (i=0; i<3; i++)           cout << Arraylnt[ i ] << " ";

    Ordenar(Arraylnt, 0, 2);     cout << endl << "Luego de ordenar: ";

    for (i=0; i<3; i++)           cout << Arraylnt[ i ] << " ";

    cout << endl << endl           << "Flotantes: " << endl           << "Arreglo original: "; 

Page 7: Plantillas c++

#include <iostream.h>#include <conio.h>

enum estado_pila { OK, LLENA, VACIA };

template <class T> class NuevaPila {    int tamanyo;    T *tabla;    int cima;   estado_pila estado; 

   public:             NuevaPila(int =10);             ~NuevaPila() { delete [] tabla; }             void meter (T);             T sacar ();             void visualizar ();             int num_elementos ();             int leer_tamanyo () { return tamanyo; }}

template <class T>NuevaPila <T> :: NuevaPila (int tam) {   tamanyo=tam;   tabla= new T [tamanyo] ;   cima=0;   estado=VACIA;} template <class T>void NuevaPila <T> :: meter (T elemento) {    if( estado!=LLENA)        tabla [cima++]=elemento;    else cout << "*** Pila llena ***";

    if(cima>=tamanyo)        estado=LLENA;     else        estado=OK; }

template <class T>T NuevaPila <T> :: sacar () {   T elemento=0;

   if(estado!=VACIA)       elemento=tabla[--cima];   else cout<<"*** Pila vac¡a ***";

   if(cima<=0)      estado=VACIA;    else       estado=OK; 

   return elemento; }

Page 8: Plantillas c++

Cuarto ejemplo

Mediante el uso de plantillas cree una clase Cola, en la que se puedan llevar a cabo operaciones como: encolar, decolar e imprimir los datos miembro. Realice una función controladora para probar el uso de esta clase.La clase NodoCola, tiene como amiga a la clase Cola.Se presenta además una función para las opciones del usuario, y que se encarga de realizar las llamadas a las funciones de las clases. Estafunción es llamada desde main.En la función main se ha usado como ejemplo una cola de enteros, aunque también se pudo haber usado otro tipo de datos como: char, double, y otros.

#include <iostream.h>#include <conio.h>

enum estado_pila { OK, LLENA, VACIA };

template <class T> class NuevaPila {    int tamanyo;    T *tabla;    int cima;   estado_pila estado; 

   public:             NuevaPila(int =10);             ~NuevaPila() { delete [] tabla; }             void meter (T);             T sacar ();             void visualizar ();             int num_elementos ();             int leer_tamanyo () { return tamanyo; }}

template <class T>NuevaPila <T> :: NuevaPila (int tam) {   tamanyo=tam;   tabla= new T [tamanyo] ;   cima=0;   estado=VACIA;} template <class T>void NuevaPila <T> :: meter (T elemento) {    if( estado!=LLENA)        tabla [cima++]=elemento;    else cout << "*** Pila llena ***";

    if(cima>=tamanyo)        estado=LLENA;     else        estado=OK; }

template <class T>T NuevaPila <T> :: sacar () {   T elemento=0;

   if(estado!=VACIA)       elemento=tabla[--cima];   else cout<<"*** Pila vac¡a ***";

   if(cima<=0)      estado=VACIA;    else       estado=OK; 

   return elemento; }

Page 9: Plantillas c++

#include <iostream.h>#include <conio.h>#include <assert.h>

template <class TIPONODO>class Cola;

///////////////////////////////////// definicion clase NodoCola ///////////////////////////////////////

template <class TIPONODO>class NodoCola {      TIPONODO dato;                         // dato      NodoCola <TIPONODO> * sig;             // puntero siguiente nodo      public:         NodoCola (const TIPONODO &);    // constructor         TIPONODO getDato() const;       // devuelve dato del nodo

      friend class Cola <TIPONODO>;          // hace que Cola sea friend};

// constructortemplate <class TIPONODO>NodoCola <TIPONODO> :: NodoCola (const TIPONODO & info)     : dato(info), sig (0) { }

// devuelve una copia del dato que esta en el nodotemplate <class TIPONODO>TIPONODO NodoCola <TIPONODO> :: getDato() const {     return dato;}

// definicion enumeracion //enum bool { false, true };

//////////////////////////////////// definicion clase Cola ///////////////////////////////////////////

template <class TIPONODO>class Cola {      NodoCola <TIPONODO> * primero;          // puntero al primer nodo      NodoCola <TIPONODO> * ultimo;           // puntero al ultimo nodo      public:         Cola ();                         // constructor         ~Cola();                         // destructor         void encolar (const TIPONODO &); // permite insertar nodo         bool decolar (TIPONODO &);       // permite eliminar nodo         bool estaVacia() const;          // verifica si la cola esta vacia         void imprimir() const;              // imprime datos de la cola

      // funci¢n de utileria para asignar un nuevo nodo

Page 10: Plantillas c++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Plantillas

[editar] Introducción

Con el objeto de explicar la razón de la necesidad de la existencia de las plantillas debemos reflexionar sobre tres paradígmas de programación anteriores, estas son: programación clásica o procedimental, programación estructurada y programación orientada al objeto POO.

Programación clásica

En el tipo de programación conocida como clásica existe una clara diferenciación entre los datos y su manipulación, es decir, entre los datos y el conjunto de algoritmos para manejarlos. Los datos son tipos muy simples y generalmente los algoritmos se agrupan en funciones orientadas de forma muy específica a los datos que deben manejar. Por ejemplo, si se escribe una función ( sort ) para ordenar en forma ascendente o descendente los números contenidos en un arreglo de números enteros, dicha función puede aplicarse a cualquier arreglo de enteros más no a arreglos de otro tipo. Aún asi, la programación clásica provee el soporte necesario para la reutilización de código ya que el código de la función se escribe solamente una vez y su reutilización se da por medio de un mecanismo conocido como llamada de función.

Programación estructurada

En la medida en que los datos que había de manipular se iban haciendo cada vez más complejos se busco la forma de agruparlos de alguna manera bajo un mismo nombre, es asi como surjen las estructuras de datos. Muchos autores se refieren a la programación estructura como a la suma de funciones y/o procedimientos más estructura de datos.

Programación Orientada al Objeto

La Programación Orientada al Objeto ( POO ) introduce nuevas facilidades y se extiende el concepto de dato, permitiendo que existan tipos más complejos, es decir, si la programación estructurada establece las bases para la manipulación de funciones y datos estructurados, la POO establece las bases para manipular datos y funciones como un solo objeto. Esta nueva habilidad viene acompañada por ciertas mejoras adicionales: la posibilidad de ocultación de determinados detalles internos irrelevantes para el usuario y la capacidad de herencia simple o múltiple.

Notas: El ocultamiento de código asi como la herencia estan presentes ( en una forma simple ) en la programación estructurada, y los mismos adquieren mucha más relevancia en la POO. Por ejemplo, en la programación estructurada si usted escribe una librería de funciones, al usuario de dicha librería solamente le informará de la existencia de tal o cual

#include <iostream.h>#include <conio.h>#include <assert.h>

template <class TIPONODO>class Cola;

///////////////////////////////////// definicion clase NodoCola ///////////////////////////////////////

template <class TIPONODO>class NodoCola {      TIPONODO dato;                         // dato      NodoCola <TIPONODO> * sig;             // puntero siguiente nodo      public:         NodoCola (const TIPONODO &);    // constructor         TIPONODO getDato() const;       // devuelve dato del nodo

      friend class Cola <TIPONODO>;          // hace que Cola sea friend};

// constructortemplate <class TIPONODO>NodoCola <TIPONODO> :: NodoCola (const TIPONODO & info)     : dato(info), sig (0) { }

// devuelve una copia del dato que esta en el nodotemplate <class TIPONODO>TIPONODO NodoCola <TIPONODO> :: getDato() const {     return dato;}

// definicion enumeracion //enum bool { false, true };

//////////////////////////////////// definicion clase Cola ///////////////////////////////////////////

template <class TIPONODO>class Cola {      NodoCola <TIPONODO> * primero;          // puntero al primer nodo      NodoCola <TIPONODO> * ultimo;           // puntero al ultimo nodo      public:         Cola ();                         // constructor         ~Cola();                         // destructor         void encolar (const TIPONODO &); // permite insertar nodo         bool decolar (TIPONODO &);       // permite eliminar nodo         bool estaVacia() const;          // verifica si la cola esta vacia         void imprimir() const;              // imprime datos de la cola

      // funci¢n de utileria para asignar un nuevo nodo

Page 11: Plantillas c++

función, asi como el objetivo y la forma correcta para comunicarse con estas, pero no es necesario que se le explique el funcionamiento interno de las mismas. Por otro lado, es bien conocido que lenguajes tales como Pascal y C, por ejemplo, dan el soporte para la creación de datos estructurados ( Record en Pascal, y struct en C ), y que dichas estructuras pueden contener a otras estructuras previamente definidas. De tal manera vemos como a los usuarios de las funciones se les oculta el código de las mismas, y que una estructura que contiene a otra hereda los miembros de la estructura contenida.

Programación genérica

La programación genérica está mucho más centrada en los algoritmos que en los datos, y su postulado fundamental puede sintetizarse en una palabra: generalización. Significa que, en la medida de lo posible, los algoritmos deben ser parametrizados al máximo y expresados de la forma más independiente posible de detalles concretos, permitiendo así que puedan servir para la mayor variedad posible de tipos y estructuras de datos.

Con el objetivo de mostrar de una manera practica las diferencias entre los tres tipos de programación mencionados arriba tomaremos como base el modelo de una vieja estructura de datos amiga de los programadores, me refiero a un array, tambien conocida por muchos como arreglo, tabla o lista. Para no entrar en polemicas de estándarización de nombrado en este capítulo diremos que la estructura modelo con la que trabajaremos es un vector ( arreglo unidimensional ).

Pues bien, dado un vector cualquiera se presenta la necesidad de crear un cierto número de funciones que sean las encargadas de la manipulación de los datos dentro del vector. Para comenzar, podemos pensar en las funciones:

1. mostrar, para desplegar o imprimir los elementos del vector.

2. ordenar, para ordenar los elementos del vector.

3. buscar, para determinar la presencia o ausencia de un determinado elemento dentro del vector.

4. insertar, para agregar componentes al vector.

5. eliminar, para quitar componentes del vector.

6. capacidad, para obtener la capacidad máxima del vector.

7. cuenta, para obtener el número de elementos actuales contenidos por el vector.

Al hacer un análisis muy detallado del problema planteado y al tratar de resolver el mismo mediante la programación clásica, veremos que, si bien es cierto que se puede llegar a la solución, para lograrlo se tendrían que establecer una serie de medidas que nos permitierán controlar de alguna manera detalles tales como: el total de elementos soportados por el vector y el número de elementos actuales contenidos por el vector. Por ejemplo, con la instrucción:

#include <iostream.h>#include <conio.h>#include <assert.h>

template <class TIPONODO>class Cola;

///////////////////////////////////// definicion clase NodoCola ///////////////////////////////////////

template <class TIPONODO>class NodoCola {      TIPONODO dato;                         // dato      NodoCola <TIPONODO> * sig;             // puntero siguiente nodo      public:         NodoCola (const TIPONODO &);    // constructor         TIPONODO getDato() const;       // devuelve dato del nodo

      friend class Cola <TIPONODO>;          // hace que Cola sea friend};

// constructortemplate <class TIPONODO>NodoCola <TIPONODO> :: NodoCola (const TIPONODO & info)     : dato(info), sig (0) { }

// devuelve una copia del dato que esta en el nodotemplate <class TIPONODO>TIPONODO NodoCola <TIPONODO> :: getDato() const {     return dato;}

// definicion enumeracion //enum bool { false, true };

//////////////////////////////////// definicion clase Cola ///////////////////////////////////////////

template <class TIPONODO>class Cola {      NodoCola <TIPONODO> * primero;          // puntero al primer nodo      NodoCola <TIPONODO> * ultimo;           // puntero al ultimo nodo      public:         Cola ();                         // constructor         ~Cola();                         // destructor         void encolar (const TIPONODO &); // permite insertar nodo         bool decolar (TIPONODO &);       // permite eliminar nodo         bool estaVacia() const;          // verifica si la cola esta vacia         void imprimir() const;              // imprime datos de la cola

      // funci¢n de utileria para asignar un nuevo nodo

Page 12: Plantillas c++

int vector[120];

se crea un arreglo con capacidad para 120 componentes de tipo entero . Ahora bien, el compilador sabe perfectamente que deberá reservar un espacio de 120 enteros para la memoria del vector, pero no se garantiza que cualquier función trate de leer o escribir datos fuera de los limites del vector. Es decir, nuestro programa no podría saber el tamaño del vector a menos que usaramos algún truco, por ejemplo usar el primer elemento del vector para contener el tamaño del mismo. Otra forma de alcanzar una solución, sería que a cada una de las funciones que tengan que ver con el vector se le pasará los parámetros: puntero de vector y número de elementos en el vector, de tal manera que, por ejemplo, la función mostrar podría declararse como:

int mostrar(int *vector, int cuenta);

[editar] Un paso hacia adelante

Si continuamos en el ámbito de la programación clásica podemos dar un paso más si es que nos valemos de tipos estructurados más elaborados. Por ejemplo, podemos definir una estructura llamada vector la cual posea los miembros: capacidad, cuenta y data como se muestra en seguida:

typedef struct vector { int capacidad; int cuenta; int *data;};

De tal manera que podriamos escribir funciones que operen sobre un solo parámetro del tipo estructurado vector. Por ejemplo, la función mostrar podría declararse como:

int mostrar(vector *v);

En este punto tendríamos que detenernos y pensar en lo siguiente:La estructura vector ( definida arriba con typedef ) es solamente un nuevo tipo de dato, es decir, podemos declarar tantas copias ( variables ) de la misma como sean necesarias, pero carece de un método constructor adecuado. Por ejemplo, la declaración:

vector nombre_var;

es válida siempre y cuando que el tipo vector ya haya sido definido, pero la variable nombre_var contendrá sólo basura hasta que no se establezcan los valores adecuados para cada uno de sus miembros ( capacidad, cuenta y data ).

[editar] Una mejor solución

Para el tipo de problemas como en el ejemplo vector y otros similares, surge la POO, misma que facilita en gran medida la solución del mismo, pero aún queda pendiente la

#include <iostream.h>#include <conio.h>#include <assert.h>

template <class TIPONODO>class Cola;

///////////////////////////////////// definicion clase NodoCola ///////////////////////////////////////

template <class TIPONODO>class NodoCola {      TIPONODO dato;                         // dato      NodoCola <TIPONODO> * sig;             // puntero siguiente nodo      public:         NodoCola (const TIPONODO &);    // constructor         TIPONODO getDato() const;       // devuelve dato del nodo

      friend class Cola <TIPONODO>;          // hace que Cola sea friend};

// constructortemplate <class TIPONODO>NodoCola <TIPONODO> :: NodoCola (const TIPONODO & info)     : dato(info), sig (0) { }

// devuelve una copia del dato que esta en el nodotemplate <class TIPONODO>TIPONODO NodoCola <TIPONODO> :: getDato() const {     return dato;}

// definicion enumeracion //enum bool { false, true };

//////////////////////////////////// definicion clase Cola ///////////////////////////////////////////

template <class TIPONODO>class Cola {      NodoCola <TIPONODO> * primero;          // puntero al primer nodo      NodoCola <TIPONODO> * ultimo;           // puntero al ultimo nodo      public:         Cola ();                         // constructor         ~Cola();                         // destructor         void encolar (const TIPONODO &); // permite insertar nodo         bool decolar (TIPONODO &);       // permite eliminar nodo         bool estaVacia() const;          // verifica si la cola esta vacia         void imprimir() const;              // imprime datos de la cola

      // funci¢n de utileria para asignar un nuevo nodo

Page 13: Plantillas c++

resolución a otro problema, es decir, hasta aquí hemos mencionado la estructura vector como un contenedor de números enteros, pero un vector podría contener caracteres, números de punto flotante y otros tipos estructurados; y los mismos algoritmos usados para ( mostrar, ordenar, buscar, etc. ) empleados en un vector de enteros, tendrían su aplicación sobre vectores de cualquier tipo. Es asi como surge lo que se conoce como PLANTILLAS o lo que es lo mismo, la programación genérica.

[editar] La clase vector desde la perspectiva de la POO

Con el objetivo de mostrar en la práctica los conceptos que hemos venido mencionando presentaremos un pequeña implementación de la clase vector. Se debe aclarar que la implementación de la misma se hará para vectores contenedores de datos tipo int solamente. Para simplificar el ejemplo, para la clase vector solamente se implementarán los métodos mostrar(), ordenar() e insertar(), asi como un método constructor base y un método destructor.

#include <iostream>#include <cstdio>#include <ctime> using namespace std; #define VECTOR_DEFAULT_SIZE 128 class vector{ // atributos int capacidad; int cuenta; int *data; public: // constructor base vector() { capacidad = VECTOR_DEFAULT_SIZE; cuenta = 0; data = new int[VECTOR_DEFAULT_SIZE]; } // destructor ~vector() { delete[] data; } // despliega todos los elementos contenidos por el vector void mostrar() { for (int t = 0; t < cuenta; t++) cout << "elemento " << t << ", valor " << data[t] << endl; } // inserta un elemento al vector int insertar(int d) {

Page 14: Plantillas c++

if (cuenta == capacidad) return -1; data[cuenta] = d; cuenta ++; return cuenta; } // ordena en forma ascendente los elementos del vector void ordenar() { int i, j, temp; int fin = cuenta; i = 0; while (i < fin ) { for ( j = i ; j < fin-1; j++) if ( data[j] > data[j+1] ) { temp = data[j]; data[j] = data[j+1]; data[j+1] = temp; } fin --; } }}; #define MAX 10int main(){ vector v; srand( time(NULL) ); for (int r = 0; r < MAX; r++) v.insertar( rand() % 100); cout << "\nvector v sin ordenar\n"; v.mostrar(); v.ordenar(); cout << "\nvector v ordenado\n"; v.mostrar(); getchar(); return 0;}

[editar] Una plantilla para la clase vector

Una vez que se llegado al entendimiento de la programación estructurada asi como de la programación orientada al objeto, se puede observar que, si bien es cierto que ambas ofrecen soluciones a problemas fundamentales tambien es cierto que las soluciones se presentan como casos especializados. Esta última afirmación la podemos ilustrar si nos fijamos en el caso del programa presentado anteriormente, en dicho programa se presenta la clase vector como un contenedor especial para números enteros (int), ahora bien, si prestamos aún aun más atención podemos llegar a la conclusión de que todos los algoritmos

Page 15: Plantillas c++

o funciones aplicadas en la clase vector pueden operar con culquier otro tipo de datos y, por lo tanto, la única diferencia sería el tipo de datos contenidos por el vector. De tal manera que aparece lo que se llama generalización o programación genérica y esta, a su vez, nos permite la creación de plantillas basadas en una lógica operatoria previamente concebida.

Con el objetivo de mostrar un ejemplo práctico retomaremos la clase vector del programa de la sección anterior y crearemos, a raiz del mismo, una plantilla. La plantilla resultante tendrá la capacidad para crear vectores de cualquier tipo.

#include <iostream>#include <cstdio>#include <ctime> using namespace std; #define VECTOR_DEFAULT_SIZE 128 template <class T> class vector{ // atributos int capacidad; int cuenta; T *data; public: // constructor base vector() { capacidad = VECTOR_DEFAULT_SIZE; cuenta = 0; data = new T[VECTOR_DEFAULT_SIZE]; } // destructor ~vector() { delete[] data; } void mostrar(); int insertar(T d); void ordenar();}; // implementación del método mostrartemplate <class T> void vector<T>::mostrar(){ for (int t = 0; t < cuenta; t++) cout << "elemento " << t << ", valor " << data[t] << endl;} // implementación del método insertartemplate <class T> int vector<T>::insertar(T d){ if (cuenta == capacidad) return -1; data[cuenta] = d; cuenta ++; return cuenta;

Page 16: Plantillas c++

} // implementación del método ordenartemplate <class T> void vector<T>::ordenar(){ T temp; int i, j, fin = cuenta; i = 0; while (i < fin ) { for ( j = i ; j < fin-1; j++) if ( data[j] > data[j+1] ) { temp = data[j]; data[j] = data[j+1]; data[j+1] = temp; } fin --; }} #define TEST 10int main(){ // prueba de un vector de números de punto flotante vector<double> v; srand( time(NULL) ); for (int r = 0; r < TEST; r++) v.insertar( (rand() % 10) * 0.5); cout << "\nvector v sin ordenar\n"; v.mostrar(); v.ordenar(); cout << "\nvector v ordenado\n"; v.mostrar(); // prueba de un vector de números long int vector<long int> v2; srand( time(NULL) ); for (int r = 0; r < TEST; r++) v2.insertar( (rand() % 100) ); cout << "\nvector v2 sin ordenar\n"; v2.mostrar(); v2.ordenar(); cout << "\nvector v2 ordenado\n"; v2.mostrar(); getchar(); return 0;}

Estructuras II

Contenido

Page 17: Plantillas c++

[ocultar] 1 Introducción

o 1.1 Pilas o Stacks

1.1.1 Pila en arreglo estático

1.1.2 Pila dinámica

o 1.2 Colas o Queues

1.2.1 Cola en un arreglo estático

o 1.3 Colas de doble enlace

IntroducciónMuchos autores comienzan por definir los conceptos de estructura de datos a raiz de estructuras conocidas como listas. En el mismo contexto, suele suceder que a dichas listas también se les conoce como secuencias y/o colecciones de datos. Hay que decir que dichos autores están (en parte) en lo correcto, ya que una lista (de cualquier tipo) es una estructura ideada con el propósito de albergar datos agrupados bajo un mismo nombre. Al respecto, podemos pensar que las listas son como arreglos de datos, es decir, para hacer una introducción al manejo y programación de listas encadenadas podemos tomar como punto de partida a los arreglos estáticos. Es así como en esta seccción se descubrirá la forma de operación de tres tipos comúnes de listas conocidas como: PILAS, COLAS Y DOBLE COLA (STACK, QUEUE, DQUEUE). En programación, el uso de listas es una práctica tan extendida que lenguajes tales como (por ejemplo) Java, Python y C++ soportan los mecanismos necesarios para trabajar con estructuras de: Vectores, Pilas, Colas, Listas, etc. En C++, los programadores que usen Dev-Cpp ( Bloodshed.software -Dev-C++ ) pueden aprovechar las ventajas que ofrecen las STL (Standard Templates Libraries) dentro de la cual se pueden encontrar plantillas para la manipulación de listas tales como: Vectores, Listas, Sets, Maps, etc. Por otro lado, los usuarios de Borland C++ ( Turbo C++ version 1.01 ) pueden hacer uso de la CLASSLIB, misma que posee las librerias para los propósitos mencionados.

Nota: En las siguientes secciones se presentarán seis programas, tres para simular listas basadas en arreglos estáticos y tres para simular listas por medio de enlaces dinámicos (punteros). En cuanto al material incluido se debe hacer las siguientes declaraciones:

1. Puesto que el material es puramente didáctico, cada programa se escribe en un mismo archivo. La idea es no perder de vista el objetivo. Los entendidos sabrán que normalmente se deben escribir archivos de cabecera, archivos de implementacion y archivos de prueba por separado.

2. Para cada una de las clases creadas en los programas se han elegido nombres en ingles. La idea es que gran parte de la documentación e implementación referente a listas está en

Page 18: Plantillas c++

dicho idioma, así, se le da al estudiante la idea básica de como operar con las librerías soportadas por los compiladores Dev-Cpp, Borlan C++, y otros.

3. Igual, se debe observar que los métodos de las clases tienen nombres en ingles, y que con el objetivo de establecer cierta estandarización todas las clases poseen los mismos métodos, aunque cada una de ellas implementa los mismos a su manera.

[editar] Pilas o Stacks

Una PILA es una estructuras en donde cada elemento es insertado y retiradodel tope de la misma, y debido a esto el comportamiento de un una pila seconoce como LIFO (último en entrar, primero en salir ).

Un ejemplo de pila o stack se puede observar en el mismo procesador, es decir, cada vez que en los programas aparece una llamada a una función el microprocesador guarda el estado de ciertos registros en un segmento de memoria conocido como Stack Segment, mismos que serán recuperados al regreso de la función.

[editar] Pila en arreglo estático

En el programa que se verá en seguida, se simula el comportamiento de una estructura de pila. Aunque en el mismo se usa un arreglo estático de tamaño fijo se debe mencionar que normalmente las implementaciones hechas por fabricantes y/o terceras personas se basan en listas dinámicas o enlazadas.

Para la implementación de la clase Stack se han elegido los métodos:

put(), poner un elemento en la pilaget(), retirar un elemento de la pilaempty(), regresa 1 (TRUE) si la pila esta vaciasize(), número de elementos en la pilaEl atributo SP de la clase Stack es el puntero de lectura/escritura, es decir, el SPindica la posición dentro de la pila en donde la función put() insertará el siguientedato, y la posición dentro de la pila de donde la función get() leerá el siguiente dato.Cada vez que put() inserta un elemento el SP se decrementa.Cada vez que get() retira un elemento el SP se incrementa.

En el siguente ejemplo se analiza lo que sucede con el SP (puntero de pila) cuando se guardan en la pila uno por uno los caracteres 'A', 'B', 'C' y 'D'. Observe que al principio el SP es igual al tamaño de la pila.

Llenando la pila.

Page 19: Plantillas c++

SP |+---+---+---+---+---+| | | | | | al principio (lista vacia)+---+---+---+---+---+ SP |+---+---+---+---+---+ push('A');| | | | | A | despues de haber agregado el primer elemento+---+---+---+---+---+

...

SP |+---+---+---+---+---+| | D | C | B | A | despues de haber agregado cuatro elementos+---+---+---+---+---+

Vaciando la pila.

SP |+---+---+---+---+---+ pop();| | D | C | B | A | despues de haber retirado un elemento+---+---+---+---+---+

...

SP |+---+---+---+---+---+| | D | C | B | A | despues de haber retirado todos los elementos+---+---+---+---+---+Nota: observe que al final la lista está vacia, y que dicho estado se debe a queel puntero está al final de la pila y no al hecho de borrar físicamente cada elementode la pila.

Ejemplo: Pila basada en un arreglo estático

#include <iostream.h> #define STACK_SIZE 256 /* capacidad máxima */typedef char almacen[STACK_SIZE]; class Stack { int SP; /* puntero de lectura/escritura */int ITEMS; /* número de elementos en lista */

Page 20: Plantillas c++

int ITEMSIZE; /* tamaño del elemento */almacen PILA; /* el almacen */ public: // constructor Stack() { SP = STACK_SIZE-1; ITEMS = 0; ITEMSIZE = 1 } // destructor ~Stack() {}; /* regresa el número de elementos en lista */int size() { return ITEMS; } /* regresa 1 si no hay elementos en la lista, o sea, si la lista está vacia */int empty() { return ITEMS == 0; } /* insertar elemento a la lista */int put(char d){ if ( SP >= 0) { PILA[SP] = d; SP --; ITEMS ++; } return d;} /* retirar elemento de la lista */int get(){ if ( ! empty() ) { SP ++; ITEMS --; } return PILA[SP];} }; // fin de clase Stack // probando la pila. // Nota: obseve cómo los elementos se ingresan en orden desde la A hasta la Z,// y como los mismos se recuperán en orden inverso.int main(){ int d; Stack s; // s es un objeto (instancia) de la clase Stack // llenando la pila for (d='A'; d<='Z'; d++) s.put(d);

Page 21: Plantillas c++

cout << "Items =" << s.size() << endl; // vaciando la pila while ( s.size() ) cout << (char)s.get() << " "; cout << "\nPara terminar oprima <Enter>..."; cin.get(); return 0;}

[editar] Pila dinámica

En el siguiente programa se presenta una implementación de una estructura dinámica tipo pila o stack. Es importante hacer notar que, a diferencia de una pila basada en un arreglo estático, una pila enlazadada dinámicamente no posee de forma natural el mecanismo de acceso por índices, en ese sentido, el programador puede crear los algoritmos necesarios para permitir tal comportamiento. En la clase que presentaremos en el ejemplo no se ha implementado el mecanismo de acceso por índices, ya que la misma se presenta como una alternativa para la simulación de una pila o stack.

Uno de los puntos más destacables en cuando al uso de listas enlazadas dinámicamente es el hecho de crear estructuras conocidas como nodos. Un nodo es una especie de eslavon ( similar al de una cadena de bicicleta ), es decir, cada nodo se enlaza con otro a través de un puntero que apunta a una estructura del mismo tipo que el nodo. Por ejemplo, para crear una estructura de nodo para almacenar enteros y a la vez para apuntar a otro posible nodo podemos emplear la sintaxis:

struct nodo { int data; nodo *siguiente;};

observe que con la declaración anterior estamos creando el tipo estructurado nodo, mismo que posee a los miembros: data para guardar valores enteros, y siguiente para apuntar o enlazar a un supuesto siguiente nodo.

Ya que las listas dinámicas inicialmente se encuentran vacias, y más aún, una lista dinámica no posee una dirección establecida en tiempo de compilación ya que las dirección de memoria que ocupará cada uno de los elementos se establecerá en tiempo de ejecución, entonces cómo determinar la condición de vacio ?. En nuestro ejemplo usaremos un contador ( ITEMS ) que dicho sea de paso, si ITEMS = 0, entonces la lista está vacia. ( la condición de vacio también podría determinarse al verificar el SP, es decir, si el SP = NULL, significa que la lista no posee elementos ).

Al hacer un análisis previo de los eventos que acontecerán en la pila y su puntero de lectura y escritura (SP, que en esta ocasión es una estructura tipo nodo), se tiene lo siguiente:

Page 22: Plantillas c++

1) Al principio la lista está vacia, en ese caso el SP es igual a NULL y, en consecuencia, el puntero next también es NULL.

SP = NULL

+------+------+ | ???? | next |--> NULL +------+------+

2) Despues de agregar el primer elemento la situación se vería asi:

SP = asignado 1 +------+------+ | data | next |--> NULL +------+------+

3) Despues de agregar otro elemento la situación se vería asi:

SP = asignado 2 1 +------+------+ +------+------+ | data | next |--> | data | next |--> NULL +------+------+ +------+------+

Ejemplo: Pila basada en un arreglo dinámico

/*---------------------------------------------------------------++ ejemplo de una pila ( STACK ) enlazada dinámicamente ++ ++ Autor: Oscar E. Palacios ++ email: [email protected] ++ ++ Manifiesto: ++ Este programa puede distribuirse, copiarse y modificarse de ++ forma libre. ++---------------------------------------------------------------*/#include <iostream>//#include <conio.h> using namespace std; /* tipo de dato que contendrá la lista */typedef char DATA_TYPE; // declaraci¢n de estructura nodostruct nodo {

DATA_TYPE data;nodo *next;

}; class StackDin { // atributos int ITEMS; /* número de elementos en la lista */ int ITEMSIZE; /* tamaño de cada elemento */ nodo *SP; /* puntero de lectura/escritura */

Page 23: Plantillas c++

public: // constructor StackDin() : SP(NULL), ITEMS(0), ITEMSIZE(sizeof(DATA_TYPE)) {} // destructor ~StackDin() {} /* agregar componente a la lista */ DATA_TYPE put(DATA_TYPE valor) {

nodo *temp;

temp = new nodo;if (temp == NULL) return -1;

temp->data = valor;temp->next = SP;SP = temp;ITEMS ++;return valor;

} int empty() { return ITEMS == 0; } /* retirar elemento de la lista */ DATA_TYPE get() {

nodo *temp;DATA_TYPE d;

if ( empty() ) return -1;

d = SP->data;temp = SP->next;if (SP) delete SP;SP = temp;ITEMS --;return d;

} }; // fin de la clase StackDin /* punto de prueba para la clase StackDin */int main(){ //clrscr(); StackDin s; DATA_TYPE d; for (d='A'; d<='Z'; d++) s.put(d); while ( ! s.empty() )

cout << (DATA_TYPE)s.get() << " ";

Page 24: Plantillas c++

cout << "\nPara terminar presione <Enter>..."; cin.get(); return 0;}

[editar] Colas o Queues

Una cola sencilla es una estructura en donde cada elemento es insertadoinmediatamente despues del último elemento insertado; y donde los elementosse retiran siempre por el frente de la misma, debido a esto el comportamientode un una cola se conoce como FIFO (primero en entrar, primero en salir).

Un ejemplo a citar de cola es el comportamiento del buffer del teclado.

Cuando en el teclado se oprime una tecla, el código del caracter ingresado es trasladado y depositado en una aréa de memoria intermedia conocida como "el buffer del teclado", para esto el microprocedador llama a una rutina específica. Luego, para leer el caracter depositado en el buffer existe otra función, es decir, hay una rutina para excribir y otra para leer los caracteres del buffer cada una de las cuales posee un puntero; uno para saber en donde dentro del buffer se escribirá el siguiente c¢digo y otro para saber de donde dentro del buffer se leerá el siguiente código.

[editar] Cola en un arreglo estático

En el programa que se ve en seguida, se simula el comportamiento de una estructura de cola simple. Aunque en el mismo se usa un arreglo estático de tamañoo fijo se debe mencionar que normalmente las implementaciones hechas por fabricantes y/o terceras personas se basan en listas dinámicas o dinamicamente enlazadas.

Para la implementación de la clase Queue se han elegido los métodos:

put(), poner un elemento en la cola get(), retirar un elemento de la cola empty(), regresa 1 (TRUE) si la cola est vacia size(), n£mero de elementos en la cola El atributo cabeza de la clase Queue es el puntero de lectura. El atributo cola de la clase Queue es el puntero de escritura.

Es decir, la cola indica la posici¢n dentro de la lista en donde la función put() insertará el siguiente dato, y la cabeza indica la posición dentro de la lista de donde la función get() leerá el siguiente dato.

Cada vez que put() inserta un elemento la cola se incrementa. Cada vez que get() retira un elemento la cabeza se incrementa.

Page 25: Plantillas c++

En el siguente ejemplo se analiza lo que sucede con la cola y la cabeza (punteros de escritura y de lectura de la Lista) cuando se guardan en la cola uno por uno los caracteres 'A', 'B', 'C' y 'D'. Observe que al principio: cola = cabeza = cero.

Llenando la cola.

cola |+---+---+---+---+---+| | | | | | al principio+---+---+---+---+---+ | cabeza cola |+---+---+---+---+---+ put('A');| A | | | | | despues de haber agregado el primer elemento+---+---+---+---+---+ | cabeza

...

cola |

+---+---+---+---+---+| A | B | C | D | | despues de haber agregado cuatro elementos+---+---+---+---+---+ | cabeza

Vaciando la cola.

cabeza |+---+---+---+---+---+| A | B | C | D | | antes de haber retirado elementos+---+---+---+---+---+ cabeza |+---+---+---+---+---+ get();| A | B | C | D | | despues de haber retirado un elemento+---+---+---+---+---+

...

cabeza |

+---+---+---+---+---+ al final| A | B | C | D | | despues de haber retirado todos los elementos+---+---+---+---+---+

|

Page 26: Plantillas c++

cola

Observese que al final el cabeza apunta hacia el mismo elemento que la cola, es decir, la cola vuelve a estar vacia. Puesto que la cola que estamos proyectando reside en un arreglo estático los componentes del arreglo aún estan dentro de la misma, salvo que para su recuperación se debería escribir otro método. En una cola dinámica (como se demostrará más adelante) los elementos retirados de la misma se eliminan de la memoria y podría no ser posible su recuperación posterior.

Nota: En el programa que aparece en seguida, al tipo de lista implementado por la clase Queue se le conoce como "lista circular" debido al comportamiento de sus punteros. Es decir si los métodos para escribir o leer detectan que el puntero correspondiente ha sobrepasado el tamaño máximo de elementos permitidos dentro de la cola, éste es puesto a cero.

Ejemplo: cola en un arreglo estático

/*---------------------------------------------------------------++ ejemplo de una cola (QUEUE) basada en un arreglo estático ++ ++ Autor: Oscar E. Palacios ++ email: [email protected] ++ ++ Manifiesto: ++ Este programa puede distribuirse, copiarse y modificarse de ++ forma libre. ++---------------------------------------------------------------*/#include <iostream.h> #define MAX_SIZE 256 /* capacidad máxima */typedef char almacen[MAX_SIZE]; class Queue { int cabeza; /* puntero de lectura */int cola; /* puntero de escritura */int ITEMS; /* número de elementos en la lista */int ITEMSIZE; /* tamaño de cada elemento */almacen alma; /* el almacen */ public: // constructor Queue() {

cabeza = 0;cola = 0;ITEMS = 0;ITEMSIZE = 1;

} // destructor ~Queue() {} // regresa 1 (true) si la lista está vacia

Page 27: Plantillas c++

int empty() { return ITEMS == 0; } // insertar elemento a la listaint put(int d){ if ( ITEMS == MAX_SIZE) return -1; if ( cola >= MAX_SIZE) { cola = 0; } alma[cola] = d; cola ++; ITEMS ++; return d;} // retirar elemento de la listaint get(){ char d; if ( empty() ) return -1; if ( cabeza >= MAX_SIZE ) { cabeza = 0; } d = alma[cabeza]; cabeza ++; ITEMS --; return d;} // regresa el n£mero de elementos en listaint size() { return ITEMS; } }; // fin de la clase Queue // probando la colaint main(){ int d; Queue q; for (d='A'; d<='Z'; d++) q.put(d); cout << "Items = " << q.size() << endl; while ( q.size() ) {

cout << (char)q.get() << " "; } cout << "\nPara terminar oprima <Enter> ..."; cin .get(); return 0;}

Ejemplo: cola en un arreglo dinámico

/*---------------------------------------------------------------++ ejemplo de una cola (QUEUE) basada en un arreglo dinámico ++ ++ Autor: Oscar E. Palacios +

Page 28: Plantillas c++

+ email: [email protected] ++ ++ Manifiesto: ++ Este programa puede distribuirse, copiarse y modificarse de ++ forma libre. ++---------------------------------------------------------------*/#include <iostream> using namespace std; typedef char DATA_TYPE; struct nodo {

DATA_TYPE data;nodo *next;

}; class QueueDin { // atributos int ITEMS, ITEMSIZE; nodo *cola, *cabeza; public: // constructor QueueDin() : cola(NULL), cabeza(NULL), ITEMS(0), ITEMSIZE(sizeof(DATA_TYPE)) {} // destructor ~QueueDin() {} /* agregar componente a la lista */ DATA_TYPE put(DATA_TYPE valor) {

nodo *temp;

temp = new nodo;if (temp == NULL) return -1;

ITEMS ++;temp->data = valor;temp->next = NULL;

if (cabeza == NULL){ cabeza = temp; cola = temp;} else{ cola->next = temp; cola = temp;}return valor;

} // regresa 1 (true) si la lista está vacia int empty() { return ITEMS == 0; }

Page 29: Plantillas c++

/* retirar elemento de la lista */ DATA_TYPE get() {

nodo *temp;DATA_TYPE d;

if ( empty() ) return -1;

d = cabeza->data;temp = cabeza->next;if (cabeza) delete cabeza;cabeza = temp;ITEMS --;return d;

} }; // fin de la clase QueueDin /* punto de prueba */int main(){ QueueDin s; DATA_TYPE d; // llenando la cola for (d='A'; d<='Z'; d++) { s.put(d); cout << d << " "; } cout << endl; // vaciando la cola while ( ! s.empty() )

cout << (DATA_TYPE)s.get() << " "; cout << "\nPara terminar presione <Enter>..."; cin.get(); return 0;}

[editar] Colas de doble enlace

Una cola doble es una estructuras en donde cada elemento puede ser insertado yrecuperado por la parte del frente (cabeza) o por la parte de atras (cola) de lalista. A diferencia de una cola sencilla, en donde solo se necesitan un método paraleer y otro para escribir componentes en la lista, en una doble cola debe haber dosmétodos para leer ( uno para leer por el frente y uno para leer por atras ) y dosmétodos para escribir ( uno para escribir por el frente y uno para escribir por atras ).

Page 30: Plantillas c++

En el programa que se verá en seguida, se simula el comportamiento de una estructura de cola doble en base a un arreglo estático. En dicho programa se declara e implementa la clase SDQueue con los siguientes métodos:

put_front(), poner un elemento en el frente de la cola put_back(), poner un elemento en la parte tracera de la cola get_front(), retirar un elemento de la parte frontal de la cola get_back(), retirar un elemento de la parte tracera de la cola empty(), regresa 1 (TRUE) si la cola est vacia size(), número de elementos en la cola

Nota: observe que para los métodos put_front() y get_front() se hace uso de la función memmove(), esto es necesario debido al hecho de que put_front() tiene que mover una posición hacia atras todos los elementos en la lista antes de insertar el componente indicado; por otro lado, la función get_front() tiene que mover una posición hacia adelante a todos los elementos que le siguen al primer elemento.

Ejemplo: doble cola en un arreglo estático

/*------------------------------------------------------------------++ ejemplo de una cola doble (DQUEUE) basada en un arreglo est tico ++ ++ Autor: Oscar E. Palacios ++ email: [email protected] ++ ++ Manifiesto: ++ Este programa puede distribuirse, copiarse y modificarse de ++ forma libre. ++------------------------------------------------------------------*/#include <iostream.h>#include <mem.h> // por memmove // using namespace std;#define MAX_SIZE 256#define t_error -1; typedef int DATA_TYPE; // máximo número de elementostypedef int almacen[MAX_SIZE]; class SDQueue { // atributos int itemsize; // tamaño de cada elemento int items; // número de elementos int cola, cabeza; // punteros de lectura y escritura almacen alma; // el almacen o arreglo public: // constructor SDQueue() : cola(0), cabeza(0), items(0), itemsize(sizeof(DATA_TYPE)) {} // destructor ~SDQueue() {}

Page 31: Plantillas c++

int empty() { return items == 0; } int size() { return items; } /* agregar componente en la parte tracera de la lista */DATA_TYPE put_back(DATA_TYPE valor){ if (items == MAX_SIZE) return t_error; alma[cola] = valor; items ++; cola ++; return valor;} /* agregar componente en la parte delantera de la lista */DATA_TYPE put_front(DATA_TYPE valor){ if (items == MAX_SIZE) return t_error; memmove((void *)&alma[cabeza+1], (void*)&alma[cabeza], items*itemsize); alma[cabeza] = valor; items ++; cola ++; return valor;} /* retirar elemento de la parte frontal de la lista */DATA_TYPE get_front(){ DATA_TYPE d; if ( empty() ) return t_error; items --; cola --; d = alma[cabeza]; memmove((void*)&alma[cabeza], (void*)&alma[cabeza+1], items*itemsize); return d;} /* retirar elemento de la parte tracera de la lista */DATA_TYPE get_back(){ DATA_TYPE d; if ( empty() ) return t_error; items--; cola --; d = alma[cola]; return d;} }; // fin de la clase SDQueue /* punto de prueba */

Page 32: Plantillas c++

int main(){ SDQueue s; DATA_TYPE d; for (d='A'; d<='Z'; d++) s.put_back(d); while ( ! s.empty() )

cout << (char)s.get_front() << " "; cout << "\nPara terminar presione <Enter>..."; cin.get(); return 0;}

Una cola doblemente encadenada es una estructuras en donde cada elemento puede ser insertado y recuperado por la parte del frente (cabeza) o por la parte de atras (cola) de la lista. A diferencia de una cola sencilla, en donde solo se necesita un puntero a un siguiente elemento, la estructura del nodo para una doble cola debe poseer un puntero a un posible siguiente elemento y un puntero a otro posible anterior elemento. Por ejemplo, para crear una estructura de nodo con doble enlace para coleccionar números enteros podemos usar la sintaxis:

struct nodo { int data; nodo *next, *prev; };

Gráficamente podemos imaginar la estructura anterior como:

+------+------+------+ <--| prev | data | next |--> +------+------+------+

En el programa que se verá en seguida, se simula el comportamiento de una estructura de cola de doble enlace. Para la implementación de la clase DDqueue en el programa se han elegido los métodos:

put_front(), poner un elemento en el frente de la cola put_back(), poner un elemento en la parte tracera de la cola get_front(), retirar un elemento de la parte frontal de la cola get_back(), retirar un elemento de la parte tracera de la cola empty(), regresa 1 (TRUE) si la cola est vacia size(), n£mero de elementos en la cola/*---------------------------------------------------------------++ ejemplo de una cola doblemente enlazada (Dqueue) basada en un ++ arreglo dinámico ++ ++ Autor: Oscar E. Palacios ++ email: [email protected] ++ ++ Manifiesto: ++ Este programa puede distribuirse, copiarse y modificarse de +

Page 33: Plantillas c++

+ forma libre. ++---------------------------------------------------------------*/ #include <iostream.h>#include <conio.h> // using namespace std; typedef char DATA_TYPE; struct nodo { DATA_TYPE data; nodo *next, *prev;}; class DDqueue { int itemsize, items; nodo *cola, *cabeza; public: // constructor DDqueue() : cola(NULL), cabeza(NULL), items(0), itemsize(sizeof(DATA_TYPE)) {} // destructor ~DDqueue() {} /* agregar componente en la parte tracera de la lista */DATA_TYPE put_back(DATA_TYPE valor){ nodo *temp; temp = new nodo; if (temp == NULL) return -1; temp->data = valor; items ++; if (cabeza == NULL ) {

temp->next = NULL;temp->prev = NULL;cabeza = temp;cola = temp;

} else{ cola->next = temp; temp->prev = cola; cola = temp; cola->next = NULL;}

return valor;}

Page 34: Plantillas c++

/* agregar componente en la parte frontal de la lista */DATA_TYPE put_front(DATA_TYPE valor){ nodo *temp; temp = new nodo; if (temp == NULL) return -1; temp->data = valor; items ++; if (cabeza == NULL ) {

temp->next = NULL;temp->prev = NULL;cabeza = temp;cola = temp;

} else{ cabeza->prev = temp; temp->next = cabeza; cabeza = temp; cabeza->prev = NULL;}

return valor;} // regresa true si la lista está vaciaint empty() { return items == 0; } /* retirar elemento de la parte frontal lista */DATA_TYPE get_front(){ nodo *temp; DATA_TYPE d; if ( empty() ) return -1; items --; d = cabeza->data; temp = cabeza->next; if (cabeza) delete cabeza; cabeza = temp; return d;} /* retirar elemento de la parte tracera de la lista */DATA_TYPE get_back(){ nodo *temp; DATA_TYPE d; if ( empty() ) return -1; items--; d = cola->data;

Page 35: Plantillas c++

temp = cola->prev; if (cola) delete cola; cola = temp; return d;} }; // fin de la clase DDqueue /* punto de prueba */int main(){ clrscr(); DDqueue s; DATA_TYPE d; // insertando elementos en la parte tracera for (d='A'; d<='Z'; d++) s.put_back(d); // insertando en la parte delantera for (d=9; d>=0; d--)s.put_front(d+'0'); // vaciando la lista while ( ! s.empty() )

cout << (DATA_TYPE)s.get_front() << " "; cout << "\nPara terminar presione <Enter>..."; cin.get(); return 0;}