TEMA 4 TDA dinámicos lineales

12
TEMA 4 TIPOS DE DATOS ABSTRACTOS DINÁMICOS LINEALES PILAS Como idea intuitiva podríamos verlo como una pila de libros de la cual solo podemos coger o mirar el primero. No se podrá acceder a los elementos anteriores al último (cima). Una pila es una estructura LIFO (ultimo en entrar primero en salir). Es tu TDA lineal y dinámico (el número de elementos no es fijo). Sin embargo su implementación puede ser dinámica, a través de punteros, o estática, mediante arreglos. Las operaciones básicas asociadas al TDA son: - PilaVacía - PilaLlena - CrearPila - Apilar - esafilar - ConsultarCima Implementaciones estáticas Definición del tipo PILA CONST MaxPila= …; TYPE TipoPila=RECORD datos : ARRAY[1..MaxPila] OF TipoDatos; cima : INTEGER; END; PROCEDURE InicioPila(VAR pila:TipoPila); BEGIN pila.cima := 0; END InicioPila; PROCEDURE PilaVacia (pila:TipoPila):BOOLEAN; BEGIN RETURN pila.cima := 0; END PilaVacia;

description

Estructuras de datos y algoritmosTEMA 4 TDA dinámicos lineales

Transcript of TEMA 4 TDA dinámicos lineales

Page 1: TEMA 4 TDA dinámicos lineales

TEMA 4 TIPOS DE DATOS ABSTRACTOS DINÁMICOS LINEALES

PILASComo idea intuitiva podríamos verlo como una pila de libros de la cual

solo podemos coger o mirar el primero.No se podrá acceder a los elementos anteriores al último (cima). Una

pila es una estructura LIFO (ultimo en entrar primero en salir).Es tu TDA lineal y dinámico (el número de elementos no es fijo). Sin

embargo su implementación puede ser dinámica, a través de punteros, o estática, mediante arreglos.

Las operaciones básicas asociadas al TDA son:- PilaVacía- PilaLlena- CrearPila- Apilar- esafilar- ConsultarCima

Implementaciones estáticas

Definición del tipo PILACONST

MaxPila= …;TYPE

TipoPila=RECORDdatos : ARRAY[1..MaxPila] OF TipoDatos;cima : INTEGER;

END;

PROCEDURE InicioPila(VAR pila:TipoPila);BEGIN

pila.cima := 0;END InicioPila;

PROCEDURE PilaVacia (pila:TipoPila):BOOLEAN;BEGIN

RETURN pila.cima := 0;END PilaVacia;

Page 2: TEMA 4 TDA dinámicos lineales

PROCEDURE Apilar(VAR pila:TipoPila; dato:TipoDatos);BEGIN

INC(pila.cima);pila.datos[pila.cima] := dato;

END Apilar;

PROCEDURE Desapilar(VAR pila:TipoPila; VAR dato:TipoDatos);BEGIN

dato := pila.datos[pila.cima];DEC(pila.cima);

END Desapilar;

PROCEDURE ConsultarPila(pila:TipoPila; VAR dato:TipoDatos);BEGIN

dato := pila.datos[pila.cima];END ConsultarPila;

Implementaciones dinámicas

Definición del tipo PILATYPE

pila= POINTER TO NodoPilaNodoPila=RECORD

datos : TipoDatos;enlace : tipopila

END;

PROCEDURE InicioPila(VAR pila:TipoPila);BEGIN

pila := NILEND InicioPila;

PROCEDURE PilaVacia (pila:TipoPila):BOOLEAN;BEGIN

RETURN pila := NIL;END PilaVacia;

PROCEDURE PilaLlena (pila:TipoPila):BOOLEAN;BEGIN

RETURN NOT Available(Size(NodoPila));END PilaLlena;

Page 3: TEMA 4 TDA dinámicos lineales

PROCEDURE Apilar(VAR pila:TipoPila; dato:TipoDatos);VAR aux: pila;

BEGINNEW(aux);aux^.datos := dato;aux^.enlace := pila;pila:=aux;

END apilar;

PROCEDURE Desapilar(VAR pila:TipoPila; VAR dato:TipoDatos);VAR aux: pila;BEGIN

NEW(aux);dato := pila^.dato;aux := pila;pila := pila^.enlace;DISPOSE (aux);

END Desapilar;

PROCEDURE ConsultarPila(pila:TipoPila; VAR dato:TipoDatos);BEGIN

dato := pila^.datos;END ConsultarPila;

Imprimir una pila:PROCEDURE ImprimirPila(pila:TipoPila);

VAR dato:TipoDatos;BEGIN

WHILE NOT PilaVacia DODesapilar(pila,dato);Imprimir(dato);

END;END ImprimirPila;

Page 4: TEMA 4 TDA dinámicos lineales

COLASEs tu TDA lineal y dinámico (el número de elementos no es fijo),

aunque la implementación puede ser dinámica, a través de punteros, o estática, mediante arreglos.

Es una estructura en la que los elementos se añaden por un extremo, denominado final de cola, pero en este caso se suprimen por el otro lado, conocido como principio de cola. Una pila es una estructura FIFO (primero en entrar primero en salir).

Las operaciones básicas asociadas a este TDA son:- Iniciarcola- ColaVacia- ColaLLena- Encolar- Desencolar- ConsultarFrente- ConsultarFinal

Nota de la implementación estática:Lo implementaremos en un Arreglo circular ya que si no según avanzáramos

acabaríamos enseguida el arreglo. Supongamos el siguiente arreglo:final frente

5 7 6 25 41 25 6 9

Esta cola estaría llena ya que frente=final+1Pero si pensamos ahora en el siguiente vector:

frentefinal

5 7 6 25 41 25 6 9Tenemos una cola de un elemento, si avanzamos el frente tendríamos

una cola vacía pero la expresión frente=final+1; la misma expresión que para la cola llena. Para solventar este problema hacemos que el frente no apunte al primer elemento sino a la posición anterior. Así una cola llena quedaría

final frente5 7 6 ----- 41 25 6 9

frente =final+1 Y una cola vacia:

finalfrente

5 7 6 ----- 41 25 6 9frente = final

Page 5: TEMA 4 TDA dinámicos lineales

Implementaciones estáticas

Definición del tipo COLA

CONSTMAXCOLA=…+1; (* perdemos una posición por la operación antes

explicada *)TYPE

TipoIndice:[1..MAXCOLA];TipoCola = RECORD

datos : ARRAY TipoIndice OF TipoDatos;frente,fina : TipoIndice;

END;

PROCEDURE InicioCola(VAR cola:Tipocola);BEGIN

cola.frente := MAXCOLA;cola.final := cola.frente;

END InicioCola;

PROCEDURE ColaVacia (cola:TipoCola):BOOLEAN;BEGIN

RETURN cola.frente := cola.final;END ColaVacia;

PROCEDURE Encolar(VAR cola:TipoCola; dato:TipoDatos);BEGIN

IF cola.fi=MAXCOLA THENcola.final := 1;

ELSEINC(cola.final);

END;cola.datos[cola.final] := dato;

END Encolar;

PROCEDURE Desencolar(VAR cola:TipoCola; VAR dato:TipoDatos);BEGIN

IF cola.frente=MAXCOLA THENcola.frente := 1;

ELSEINC(cola.frente);

END;Dato := cola.datos[cola.final];

END Desencolar;

PROCEDURE Consultarfrente(cola:TipoCola; VAR dato:TipoDatos);BEGIN

IF cola.frente=MAXCOLA THENdato := cola.datos[1];

ELSEdato := cola.datos[cola.frente+1];

END;

Page 6: TEMA 4 TDA dinámicos lineales

END Consultarfrente;

PROCEDURE ConsultarFinal(cola:TipoCola; VAR dato:TipoDatos);BEGIN

dato := cola.datos[cola.final];END ConsultarFinal;

Implementaciones dinámicas

Definición del tipo PILATYPE

Ptr_nodo=POINTER TO NodoColaNodoCola= RECORD

Datos : TipoDatos;enlace : Ptr_Nodo;

END;TipoCola= RECORD

final,frente : Ptr_Nodo;END;

PROCEDURE InicioCola(VAR cola:Tipocola);BEGIN

cola.final := NIL;END InicioCola;

PROCEDURE ColaVacia (cola:TipoCola):BOOLEAN;BEGIN

RETURN cola.final := NIL;END ColaVacia;

PROCEDURE Consultarfrente(cola:TipoCola; VAR dato:TipoDatos);BEGIN

dato := cola.frente^.datos;END Consultarfrente;

PROCEDURE ConsultarFinal(cola:TipoCola; VAR dato:TipoDatos);BEGIN

dato := cola.fi^.datos;END ConsultarFinal;

PROCEDURE Desencolar(VAR cola:TipoCola; VAR dato:TipoDatos);VAR

aux:Ptr : Nodo;BEGIN

NEW(aux);dato := cola.frente^.datos;aux:=cola^.frente;cola.frente:=Cola.frente^.enlace;DISPOSE(aux);

END Desencolar;

PROCEDURE Encolar(VAR cola:TipoCola; dato:TipoDatos);

Page 7: TEMA 4 TDA dinámicos lineales

BEGINNEW(aux);aux^.datos := dato;aux^.enalce := cola.frente;IF ColaVacia(Cola) THEN

Cola.frente := aux;ELSE

Cola.final^.enlace := aux;ENDcola.final := aux;

END Encolar;

Page 8: TEMA 4 TDA dinámicos lineales

CONSIDERACIONES GENERALESAntes de finalizar es conveniente realizar algunas consideraciones

generales con el fin de ver con una perspectiva de conjunto los conceptos presentados en este tema y relacionarlos con otros ya conocidos.

1. A lo largo del rema se han ido analizando diversos TDA y diferentes algoritmos. En ocasiones, se han encontrado soluciones que no son adecuadas aunque ‘funcionen’. Debemos insistir en este punto. No todo lo que funciona es la solución correcta. Recordemos el ejemplo de la implementación de la cola mediante una estructura dinámica. Una lista doblemente enlazada no es adecuada por su innecesario coste de almacenamiento y procesamiento (pero funciona), y una lista lineal con un único puntero externo tampoco es adecuada por su coste computacional (aunque también funciona).

La conclusión es clara: la lista enlazada con dos punteros externos (frente y final) es la solución adecuada. La idoneidad de una solución vendrá dada, como siempre, por los criterios de economía de almacenaje y coste computacional.

2. En el Capitulo I ya se definió un TDA dinámico como aquel en el que el número de elementos que lo componen es variable. En este capítulo se han definido las pilas y las colas y se ha comentado su naturaleza dinámica. Posteriormente se ha estudiado su implementación estática y dinámica. Por otro lado, una definición alternativa (y también correcta) de una estructura dinámica es la siguiente: aquella estructura que puede aumentarse o reducirse en tiempo de ejecución. ¿Es esto contradictorio con el hecho de que una pila, por ejemplo, implementada mediante arreglos sea dinámica? La respuesta es claramente no. Los tipos de datos abstractos son estáticos o dinámicos dependiendo exclusivamente de si definición, nunca de su implementación. Así en la implementación estática no debe confundirse la pila con el arreglo. El arreglo no crece ni disminuye en tiempo de ejecución, pero la pila sí. Las componentes del arreglo que no han sido ocupada introduciendo datos en la pila no forman parte de ésta. Tan dinámica es una pila implementada mediante arreglos como una implementada con una lista enlazada.

3. Las implementaciones estáticas tienen la ventaja de que son más rápidas. El manejo de arreglos utilizando el índice es más rápido que la realización del conjunto de manipulaciones de punteros que son necesarias en las estructuras basadas en variables dinámicas.

4. La clave fundamental para decidir entre las implementaciones estáticas y dinámicas de tipos de datos abstractos dinámicos radica en el hecho de si se conoce o no a priori un número máximo de datos que deberán ser almacenados. Si este número máximo es conocido, la implementación estática no es sólo posible sino que es más adecuada atendiendo a las consideraciones expuestas en el punto 3. Como ejemplo ilustrativo considérese el ejemplo de la evaluación de la parentización de una expresión en notación infija.

Al solucionar este ejercicio de programación se llegó a la conclusión de que l TDA adecuado es la pila. La siguiente cuestión a resolver era si debe ser estática o dinámica. En el primer caso (a) la especificación decía que las cadenas se leían desde la consola. Si las consolas tienen un buffer que acepta un número limitado de caracteres, éste puede ser conocido a priori. Por tanto, es posible una implementación estática y atendiendo a las consideraciones realizadas en el punto 3 es más adecuada. Sin embardo, en el

Page 9: TEMA 4 TDA dinámicos lineales

segundo caso (b) las cadenas debían leerse desde un fichero. Entonces no podemos conocer a priori un número máximo de caracteres que tienen que almacenarse. Por tanto, debería utilizarse una implementación dinámica.

5. También debe tenerse en cuenta que la utilización de un TDA dinámico para resolver un problema en el que el número de elementos a almacenar es variable no es siempre adecuada. Supongamos, por ejemplo, que se necesita almacenar un apellido en una estructura de datos, y que las operaciones a realizar con él descartan la utilización de una pila o una cola. Tendremos que considerar un arreglo o una lista enlazada. Como los apellidos tienen diferente cantidad caracteres podría pensarse que su almacenamiento en una lista enlazada es más adecuado que en un arreglo. Sin embargo, esto no es cierto. Es verdad que el número de elementos es variable, pero por otro lado sabemos que el número de caracteres es limitado (¿Cuántos apellidos tienen más de quince caracteres?, ¿o más de veinticinco?). Si se utilizase una lista enlazada para cada apellido se ahorraría la memoria de las posiciones en las que no hay caracteres. Pero también debe tenerse en cuenta que se gastaría memoria para almacenar los punteros de los nodos (y un carácter ocupa menos que una dirección) y además su manejo es más lento como se indicó en 3. Por tanto, la solución con un arreglo es la adecuada.

6. Por último, es muy importante realizar una consideración acerca de la implementación Vaciar una pila o una cola que contiene elementos, Como Vaciar no es un operador básico hay que implementarla en función de los operadores básicos de la misma. En sentido estricto hay que sacar todos los elementos hasta que la pila o la cola esté vacía. Si se piensa en las implementaciones con arreglos Vaciar puede implementarse mediante una simple llamada a Iniciar, ya que los demás antiguos elementos del arreglo serán “basura” cuando se haya iniciado. Sin embargo, hacer esto con una implantación dinámica tiene resultados catastróficos puesto que la lista enlazada sobre la que se implementó la pila o la cola no ha sido liberada, ocupa memoria y no estará ya accesible para liberarla. Éste es un error muy grave. Entonces, ¿hay que considerar la implementación para realizar las funciones sobre los TDA? Es decir, por un lado tendremos que desarrollarlas en función de los operadores básicos y auxiliares definidos sobre ellas, pero por otro lado Vaciar sacando todos los elementos con una implementación estática tiene un coste computacional innecesario. La solución en sentido estricto es realizar la función sin atender a los detalles de implementación, aunque el coste computacional sea innecesario. Sin embargo, observando el hecho, una solución elegante es definir un nuevo TDA en el que se incorpore la operación Vaciar entre las básicas, llamándola por ejemplo Pila con vaciado, o Cola con vaciado. No debe nunca olvidarse que los TDA se definen de forma estricta pero siempre está permitido definir cualquier TDA que sea necesario. Lo importante es evitar ambigüedades.

CONCLUSIONES

En conclusión, no existen reglas ni para decidir de forma absoluta entre los TDA dinámicos o estáticos ni tampoco para concluir que una implementación dinámica es siempre mejor que una estática para las

Page 10: TEMA 4 TDA dinámicos lineales

estructuras dinámicas. Sin embargo, sí se dispone de criterios claros para adoptar la solución adecuada al resolver un problema concreto. Estos criterios son la economía de almacenamiento y el coste computacional. Como sucedía en los algoritmos de clasificación se deben conocer todas las posibilidades, en este caso los TDA y sus posibles implementaciones, y al resolver unas especificaciones dadas elegir razonablemente las más adecuadas.

En este capítulo se han presentado los TDA dinámicos lineales fundamentales para la organización de datos, que mantienen una organización secuencial con un predecesor y su sucesor. En primer lugar se han introducido, como ejemplos de construcción de TDA dinámicos, algunos similares a las listas enlazadas. Seguidamente se han estudiado detalladamente los dos TDA dinámicos lineales más característicos: las pilas y las colas, desarrollando completamente sus implementaciones, tanto estáticas como dinámicas, y se han explorado las diversas posibilidades hasta llegar a una implementación determinada satisfactoria. Como es habitual, en ocasiones se han encontrado soluciones que no son adecuadas aunque ‘funciones’.

Debe observarse que se ha insistido en el hecho, bien conocido y detallado desde el comienzo del texto, de que el carácter estático o dinámico del TDA es independiente de su implementación. Las implementaciones estáticas tienen la ventaja de que son más rápidas, mientras que las dinámicas permiten un mejor aprovechamiento de la memoria. La clave fundamental para decidir entre las implementaciones estáticas y dinámicas de tipos de datos abstractos dinámicos radica en el hecho de si se conoce o no a priori un número máximo de datos que deberán ser almacenados. Sin embargo, esto no significa que la utilización de un TDA dinámico para resolver un problema en el que el número de elementos a almacenar es variable no es siempre adecuada.

En conclusión, no existen reglas ni para decidir para todos los casos que un TDA es más adecuado ni para considerar únicamente una implementación determinada. El estudio de los conceptos desarrollados en este capítulo permite disponer de criterios claros para adoptar la solución adecuada al resolver un problema concreto.