TIPOS ABSTRACTOS DE DATOS - TADS


4.1 Introducción
4.2 Definición y Concepto
4.3 Representación de un Objeto
4.4 Invariante de un TAD
4.5 Especificación de un TAD
4.6 Clasificación de las operaciones
4.7 Manejo de error
4.8 Metodología de diseño de TAD's

4.1 Introducción

El objetivo del estudio de las estructuras de datos es la representación de la información (datos) que permitan obtener un algoritmo lo más sencillo posible, para lo cual se tiene en cuenta:

Ejemplo 4.1:- Problemas a enfrentar

- Buscar un libro en la biblioteca

- Uso de números romanos o arábigos  

Los problemas reales tienden a ser complejos porque involucran demasiados detalles, y resulta imposible considerar todas las posibles interacciones a la vez, en este aspecto la abstracción constituye una herramienta en la especificación de un TAD, ya que por medio de esta capacidad solo se tienen en cuenta los aspectos más relevantes del problema objeto de análisis y a partir de la abstracción se determina "el que" del problema a tratar, sin preocuparse de entrada por los aspectos de la implementación ("el como").

El razonar en términos de abstracciones conlleva una serie de ventajas:

La evolución de la Programación muestra una tendencia a incluir mecanismos de abstracción cada vez de más alto nivel :

Figura 4.1 Relación Especificación - Abstracción - Implementación

La figura 4.1 representa la abstracción como una barrera entre la especificación y la implementación. Los clientes de una entidad solo conocen la parte de la especificación que les permite utilizar la entidad sin preocuparse por la implementación.

Para entender el concepto de tipo abstracto de datos analicemos la diferencia entre los tipos predefinidos y los tipos definidos por el programador.

Ejemplo 4.2:- Ejemplo TAD deficiente

Si para definir un tipo de datos para representar fechas, utilizamos una representación como esta:
typedef int TDia;
typedef enum { enero, febrero, ... , diciembre } TMes;
typedef int TAnyo;
typedef struct { TDia dia; TMes mes; TAnyo anyo; } TFecha;

Debido a que se tiene libre acceso a la representación del tipo de datos, es posible realizar operaciones absurdas con respecto a la semántica, como:  

fecha.mes = febrero;
fecha.dia = 30;

Al decir que TFecha es un TAD debe poseer las operaciones que restrinjan la asignación de valores erróneos como el día 30 al mes de febrero.

4.2 Definición y Concepto

Un tipo de dato abstracto o TDA es un modelo matemático compuesto por una colección de operaciones definidas sobre un conjunto de objetos abstractos que modelan elementos del mundo, donde dichas operaciones simulan el comportamiento que el elemento modelado tiene en el mundo del problema.

El concepto de tipo de dato abstracto (TDA, Abstract Data Types ), fue propuesto por primera vez hacia 1974 por John Guttag y otros, pero no fue hasta 1975 que por primera vez Liskov lo propuso para el lenguaje CLU.

Un TDA está caracterizado por un conjunto de operaciones (funciones) al cual se le denomina usualmente como su interfaz pública y representa el comportamiento del TDA; mientras que la implementación (como la parte privada del TDA) está oculta al programa cliente que lo usa. Todos los lenguajes de alto nivel tienen predefinidos TDA; que son los tipos denominados simples y las estructuras predefinidas, y estos tienen sus interfaces públicas que incluyen las operaciones como la +, -, *, etc.

Cuando se habla de un TDA no se hace ninguna alusión al tipo de los elementos sino tan sólo a la forma en que están dispuestos estos elementos. Sólo interesa la estructura que soporta la información y sus operaciones. Para determinar el comportamiento estructural basta con observar la conducta que seguirán los datos.

Un TDA tendrá una parte que será invisible al usuario la cual hay que proteger y que se puede decir que es irrelevante para el uso del usuario y está constituida tanto por la maquinaria algorítmica que implemente la semántica de las operaciones como por los datos que sirvan de enlace entre los elementos del TDA, es decir, información interna necesaria para la implementación que se esté haciendo para ese comportamiento del TDA. Resumiendo podemos decir, que tanto la implementación de las operaciones como los elementos internos del TDA serán privados al acceso externo y ocultos a cualquier otro nivel.

Un TDA representa una abstracción:

Se puede decir que un TAD es un tipo de dato, que se agrega al lenguaje de programación, para representar un elemento involucrado en el problema que se desea resolver. De esta forma se le permite al lenguaje que se le acerque al mundo del problema, manejando los datos que allí se encuentran. En el proceso de desarrollo de software, dentro del mundo del problema casi siempre es posible identificar entidades que permiten expresar la solución en términos más sencillos, más fáciles de mantener y de probar.

Un tipo abstracto de datos se compone de:

4.2.1 Encapsulamiento:

El encapsulamiento consiste en aislar las cuestiones de implementación de las de especificación, es decir, en esconder los detalles de implementación de un determinado objeto, sea este un tipo de dato o un algoritmo, y mostrar tan sólo su especificación.

De este modo, nos centraremos en el qué y ocultaremos el cómo. Por ejemplo, en el caso del tipo de datos REAL, el lenguaje proporciona al usuario la capacidad de definir variables de este tipo, de acceder y modificar su contenido, de realizar operaciones aritméticas con las mismas. Sin embargo, el usuario no tiene que preocuparse de cómo se almacenan los distintos números reales, ni del tratamiento que es necesario realizar con sus representaciones binarias para sumarlos o multiplicarlos. La técnica que se utiliza para lograr la ocultación de la información es el encapsulamiento.

El uso de la abstracción y el ancapsulamiento proporcionan varias ventajas a la hora de desarrollar programas complejos o definir nuevos tipos de datos:

4.3 Representación de un Objeto Abstracto

Al comenzar con el proceso de diseño de un TAD es necesario tener una representación abstracta del objeto sobre el cual se quiere trabajar, sin necesidad de establecer un compromiso con ninguna estructura de datos concreta, ni con ningún tipo de lenguaje de programación seleccionado. Esto va a permitir expresar las condiciones, relaciones, restricciones y operaciones de los elementos modelados, sin necesidad de restringirse a una representación interna concreta.

El primer paso en el proceso de modelado de un TAD consiste en definir el estado interno del objeto abstracto por medio de algún formalismo matemático, gráfico o descriptivo

Ejemplo 4.3:- Descripción TAD Matriz

TAD Matriz

0     k m-1
0
         
         
         
i
      xi,k  
n-1
         

Con esta notación es posible hablar de cada uno de los componentes de una matriz, de sus dimensiones, de la noción de fila y columna, de la relación entre elementos, sin necesidad de establecer unas estructuras de datos concretas para manejarlos.  

Ejemplo 4.4:- Descripción TAD Diccionario

<[Palabra1, <s11,...,s1k>], [Palabra2, <s21,...,s2k>], [PalabraN, <sN1,...,sNk>]>

En esta notación, se hacen explícitas agunas características del elemento diccionario, que está formado por un conjunto de palabras que a su vez posee un conjunto de significados.

4.4 Invariante de un TAD

El invariante de un TAD establece la validez para cada uno de sus objetos abstractos en términos de condiciones sobre su estructura interna y sus componentes, indicando en que casos un objeto abstracto modela un elemento posible del mundo del problema. Estructuralmente, el invarianrte esta compuesto por condiciones que restringen el dominio de los componentes internos y por relaciones entre ellos.

El invariante está relacionado con la corrección de la implementación del TAD en los siguientes aspectos:

Lo importante no es escribir el invariante de la representación formalmente, sino determinar (aún con una descripción informal) de entre todos los valores que puede tomar el tipo representante cuáles representan valores válidos del TAD que estamos diseñando.

Ejemplo 4.5:- Invariante TAD Diccionario

TAD Diccionario: <[Palabra1, <s11,...,s1k>], [Palabra2, <s21,...,s2k>], [PalabraN, <sN1,...,sNk>]>

El invariante debe incluir condiciones como:
- Las palabras están ordenadas ascendentemente y no hay repetidas -> elem(i).palabra<elem(i+1).palabra, 1<=i<=N
- Los significados están ordenados ascendentemente y no hay repetidos -> elem(i).sig(r)<elem(i).sig(r+1), 1<=i<=N, 1<=r<=k
- Toda palabra tiene por lo menos asociado un significado -> Para todo elem(i)=[palabra,<sig(1),...,sig(k)>], k>0.

Si un objeto del TAD no cumple cualquiera de estas condiciones, implica que no se encuentra modelando un elemento del TAD y por lo tanto la representación no es válida.

4.5 Especificación de un TAD

La especificación de un TAD debe cumplir con que es precisa, es general, es legible y no presenta ambigüedad

Una especificación para un tipo abstracto de datos consta de:
— La identificación del conjunto de valores posibles y,
— La especificación pre/post de cada una de las operaciones.

Inicialmente la especificación de un TAD parte de una metodología semi - formal, donde se especifican Tipo, Sintaxis y Semántica del TAD que se está modelando.

4.5.1 Especificación semiformal

TAD: Nombre del Tipo

Sintaxis: Sintaxis de las operaciones
        operacion(listado de tipo de argumentos): tipo del resultado

Semántica: Efecto de las operaciones
        operacion(valores concretos) =>expresión del resultado

Ejemplo 4.6:- Especificación Semi - Formal TAD Natural

TAD: Natural

Sintaxis:

Cero:Natural
Sucesor(Natural):Natural
Escero(Natural):Booleano
Igual(Natural,Natural):Booleano
Suma(Natural,Natural):Natural

Semántica: Para todo n,m que pertenecen al tipo Natural

EsCero(Cero) => Verdadero
EsCero(Sucesor(n)) => Falso
Igual(Cero,n) => EsCero(n)
Igual(Sucesor(n),Cero) => Falso
Igual(Sucesor(n),Sucesor(m)) => Igual(n,m)
Suma(Cero,n) => n
Suma(Sucesor(n),m) => Sucesor(Suma(m,n))

Ejemplo 4.7:- Especificación Semi - Formal TAD Bolsa

Definir el TAD bolsa como una colección de elementos no ordenados, con repetición.

Las operaciones a definir son: BolsaVacia, Agregar, EsVacia, Esta, Cuantos, Sucesor, Unión, Total, Intersección.

BolsaVacia: Crea una bolsa sin ningún elemento.
Agregar: Agrega un elemento a la lista
EsVacia: Visualiza si una bolsa está vacia.
Esta: Decide si un elemento se encuentra dentro de una bolsa.
Cuantos: Indica la acntidad de veces que esta repetido un elemento
Sucesor: Indica el cardinal más uno.
Total: Indica el cardinal de la bolsa.
Unión: Construye la bolsa unión de dos bolsas
Intersección: Construye la bolsa intersección de dos bolsas dadas.

TAD: Bolsa
Valores: bolsa de elementos ordenados que pueden repetirse
Operaciones: BolsaVacia, Agregar, EsVacia, Esta, Cuantos, Unión, Sucesor,Total, Intersección

Sintaxis:

BolsaVacia: Bolsa.
Agregar(Bolsa, Elemento): Bolsa
EsVacia(Bolsa): Boolean
Esta(Bolsa, Elemento): Boolean
Cuantos(Bolsa, Elemento): Natural
Sucesor(Bolsa): Natural
Total(Bolsa): Natural
Unión(Bolsa, Bolsa): Bolsa
Intersección(Bolsa, Bolsa): Bolsa

Semántica: Sean B,C de tipo Bolsa; e, e1 de tipo elemento

Agregar(Agregar (B, e), e1) => Agregar(Agregar (B, e1), e)
EsVacia(BolsaVacia) => True
EsVacia(Agregar (B, e)) => False
Esta(BolsaVacia, e) => False
Esta(Agregar (B, e), e1) => Si igual(e,e1) entonces True
                            Si_no Esta(B, e1)
Cuantos(BolsaVacia, e): Cero
Cuantos (Agregar (B, e), e1) => Si igual(e,e1) entonces Sucesor(Cuantos (B, e1))
                                       Si_no Cuantos (B, e1)
Sucesor(BolsaVacia) => Cero
Total(BolsaVacia) => Cero
Total(Agregar (B, e)) => Sucesor(Total(B))
Union(B, BolsaVacia) => BolsaVacia
Union(B, Agregar (C, e)) => Agregar (Union (C, B), e)
Interseccion(B, BolsaVacia) => BolsaVacia
Interseccion(B, Agregar (C, e)) => Si Esta(B,e) entonces Agregar (Interseccion (B, C),e)
                                Si_no Interseccion (B, C)

4.5.2 Especificación formal

De manera formal el TAD se puede especificar de la a partir del siguiente esquema:

Tabla 4.1 Esquema Especificación TAD

Especificación TAD
TAD: Nombre
Descripción objeto abstracto (Gráfica o Textual)
Invariante del TAD

Operaciones:
operacion1(listado de tipo de argumentos): tipo del resultado

 

operacionn(listado de tipo de argumentos): tipo del resultado

Prototipo operacion1
/*Descripción operación*/
{precondiciones: ...}
{postcondiciones: ...}

Las precondiciones y postcondiciones pueden referirse, únicamente, a los elementos que componen el objeto abstracto y a los argumentos que recibe. No pueden incluir ningún otro elemento del contexto en ele cual se van a ejecutar. En la especificación de las operaciones, se debe considerar implícito en la precondición y postcondición, que el objeto abstarcto sobre el cual se va a operar cumple el invariante.

Es importante proporcionar un abreve descripción de cada operación, de manera que el cliente pueda darse una rápida idea de los servicios que un TAD ofrece, sin necesidad de entrar a hacer una interpretación de su especificación formal.

Al seleccionar los nombres de las operaciones se debe tener en cuenta que no pueden existir dos operaciones con el mismo nombre en un programa, incluso si pertenecen a TAD diferentes. Por esta razón es recomendable agregar un mismo sufijo a todas las operaciones de un TAD, de tal forma que las identifique.

Ejemplo 4.8:- Especificación TAD Matriz

Especificación TAD Matriz
TAD: Matriz

Conjunto de valores enteros agrupados en n filas y m columnas, donde cada elemento se puede referenciar a partir de la columna y fila que ocupa dentro del objeto.

0     k m-1
0
         
         
         
i
      xi,k  
n-1
         

 

Invariante: n>0,m>0

Operaciones:
CrearMat(entero,entero): Matriz
AsignarMat(Matriz,entero,entero,entero): Matriz
InfoMat(Matriz,entero,entero): entero
FilasMat(Matriz): entero
ColsMat(Matriz): entero

Matriz CrearMat(int filas,int cols)
/*Construye y retorna una matriz de filas-1 filas y cols-1 columnas, inicializando todos sus elementos a cero*/
{precondiciones: filas>0,cols>0}
{postcondiciones: CrearMat es una matriz de [0..fila-1,0..cols-1],x[i,k]=0}
void AsignarMat(Matriz mat,int fila,int col,int valor)
/*Asigna a la celda [fila,col] el valor de valor*/
{precondiciones: 0<=fila<n,0<=col<m}
{postcondiciones: mat[fila,col]=valor}
int InfoMat(Matriz mat,int fila,int col)
/*Retorna el contenido de la celda [fila,col]*/
{precondiciones: 0<=fila<n,0<=col<m}
{postcondiciones: InfoMat=mat[fila,col]}
void FilasMat(Matriz mat)
/*Asigna a la celda [fila,col] el valor de valor*/

{postcondiciones: FilasMat= n}
void ColsMat(Matriz mat)
/*Asigna a la celda [fila,col] el valor de valor*/

{postcondiciones: ColsMat= m}

El invariante del TAD Matriz solo establece una restricción para el número de filas y columnas del objeto abstracto. El TAD matriz cuenta con 5 operaciones que permiten realizar las operaciones básicas para manejar un objeto del TAD, con lo cual es posible resolver cualquier problema que involucre una matriz.

4.6 Clasificación de las operaciones de un TAD

Las operaciones que implemeta un TAD se clasificacn en tres grupos principales, de acuerdo a la función que realiza sobre el objeto abstracto.

Adicionalmente a los tipos de operación básicos existen algunas subcategorías de estas, que le agregan portabilidad al TAD. Dentro de estas operaciones se encuentran las de Comparación, Copia, Destrucción, Salida a pantalla y Persistencia (son operaciones que le permiten a la instancia del TAD persistir a la ejecución del programa que lo utiliza).

4.7 Manejo de Error

El manejo de errores es uno de los aspectos relevantes durante el proceso de diseño de un TAD. Por lo tanto es conveniente considerar los siguientes aspectos:

4.8 Metodología para el diseño de TADS

Para el diseño de un TAD, generalmente se siguen los siguientes pasos:

El contenido de esta página esta basado en el material disponible en:


INGENIERO NESTOR DIAZ
FIET - UNICAUCA
2005