Ejemplo de Tipo Abstracto de Datos

Lista ordenada con acceso basado en cursor

1. Objetivos

En ésta página se presenta un ejemplo de definición de un tipo abstracto de datos (TAD) en Pascal, que representa una lista ordenada de elementos a los que se accede mediante cursor: De todos los elementos de la lista, en un momento dado sólo uno de ellos es accesible, al que se le llama cursor o elemento actual. Existen operaciones para hacer que el elemento actual sea el primero de la lista o para hacer que pase a ser el elemento que sigue al que era el actual. Mediante esas dos operaciones es posible acceder a todos los elementos de la lista.

Existen situaciones en las que el elemento actual no está definido: Cuando la lista estáa vacía, cuando se pasa al siguiente del último elemento, cuando se reordena la lista, cuando se busca un elemento de valor mayor que todos los existentes y cuando se borra el último elemento. En esos casos, al requerir el elemento actual se obtiene el valor nil.

Las operaciones de acceso y borrado se realizan sobre el elemento actual. La operación de inserción garantiza que el nuevo elemento se inserte en la posición adecuada de forma que la lista se mantenga siempre ordenada.

El definir el orden de los elementos es responsabilidad de quien utilize este TAD, el cual debe definir una función que se encargue de comparar dos elementos, y proporcionar al TAD una referencia a esa función para que pueda utilizarla cuando lo necesite. Este esquema permite, además, reordenar los elementos de la lista de acuerdo a un criterio distinto cuando sea necesario.

 

2. Definición del TAD Lista Ordenada

El siguiente listado muestra las operaciones que se pueden realizar sobre una lista ordenada, y los parámetros de entrada y salida de cada una. Se puede observar que todas reciben como entrada la lista sobre la que se realiza la operación. Exceptuando ElemActual y ListaLlena, todas las operaciones realizan cambios en el estado interno de la lista, y por lo tanto devuelven la lista modificada, por eso utilizan un paso por variable.

    procedure Inicializar(var L: TListaOrd; fMenorIgual: TFuncComp);
    procedure Destruir(var L: TListaOrd);
    function  ListaLlena(L: TListaOrd) : boolean;
    function  ElemActual(L: TListaOrd) : pointer;
    procedure IrAInicio(var L: TListaOrd);
    procedure IrASiguiente(var L: TListaOrd);
    procedure Buscar(var L: TListaOrd; Elem: pointer);
    procedure Insertar(var L: TListaOrd; Elem: pointer);
    procedure Borrar(var L: TListaOrd);
    procedure Reordenar(var L: TListaOrd; fMenorIgual: TFuncComp);

A continuación se muestra una tabla con las precondiciones y postcondiciones de cada operación. En principio, se puede asumir que las precondiciones representan los requisitos que se deben cumplir antes de llamar a esa operación, y por lo tanto son condiciones que debe garantizar el programa que desee utilizar esa operación. Las postcondiciones representan, en cierto modo, el propósito u objetivo de la operación, y son condiciones que la unidad que implementa el TAD garantiza que se van a cumplir tras la ejecución de la operación (siempre que se hallan cumplido las precondiciones).

En el tema 5 (Verificación) se verá una descripción más formal de las precondiciones y las postcondiciones, y de cómo se derivan de la técnica de programación bajo contrato.

OperacionesPrecondicionesPostcondiciones
Inicializar Ninguna Inicializa la lista asignando la función de comparación proporcionada y estableciendo el número de elementos a cero y el elemento actual a ninguno.
Destruir Lista inicializada Se libera la memoria interna utilizada para representar la lista. Se establece el número de elementos a cero y el elemento actual a ninguno.
Lista llena Lista inicializada Comprueba si queda espacio en la lista para insertar un nuevo elemento.
Elemento actual Lista inicializada Se devuelve la dirección de memoria correspondiente al elemento actual de la lista, o el valor nil si no existe elemento actual o la lista está vacía.
Ir a inicio Lista inicializada El elemento actual pasa a ser el primero de la lista. Si la lista está vacía el elemento actual pasa a ser nil.
Ir a siguiente Lista inicializada El nuevo elemento actual pasa a ser el elemento que sigue en la lista al anterior elemento actual. Si el anterior elemento actual no existía o era el último el elemento actual pasa a ser nil.
Buscar Lista inicializada El elemento actual pasa a ser el primer elemento de la lista igual o mayor que el valor proporcionado. Las comparaciones entre elementos se realizan utilizando la función de comparación proporcionada en última llamada a Reordenar, o bien, si no se ha realizado ninguna, en la llamada a Inicializar. Si la lista está vacía o el valor proprocionado es mayor que todos los que existen en la lista, el elemento actual pasa a ser nil.
Insertar Lista inicializada y no llena. Se inserta el elemento dentro de la lista de forma que su elemento siguiente (si existe) sea estrictamente mayor y su elemento anterior (si existe) sea menor o igual. Las comparaciones entre elementos se realizan de la manera descrita en la operación Buscar. El elemento actual pasa a ser el elemento insertado.
Borrar Lista inicializada y elemento actual distinto de nil Se elimina el elemento actual de la lista. El nuevo elemento actual pasa a ser el siguiente al elemento eliminado. Si se elimina el último elemento de la lista el elemento actual pasa a ser nil.
Reordenar Lista inicializada Se asigna la función de comparación proporcionada a la lista y se reordenan los elementos de acuerdo a la nueva función de comparación. El elemento actual pasa a ser nil.

 

3. Implementaciones del TAD

Se proporcionan dos implementaciones distintas de este TAD: Una basada en arrays y otra basada en listas simplemente enlazadas. Aunque ambas se diferencian en la manera en que se almacenan los elementos y se realizan las operaciones, es importante darse cuenta que un programa que utilize este TAD no necesita tener esos cambios en cuenta: Dentro del programa, basta cambiar la linea uses Lista1 por uses Lista2 para que funcione con una u otra implementación y los resultados (excepto por el orden asintótico de las operaciones) serán exactamente los mismos.

OperacionesOrden asintóticoAlgoritmo
Inicializar O(1) Trivial
Destruir O(1) Trivial
Lista llena O(1) Trivial
Elemento actual O(1) Trivial
Ir a inicio O(1) Trivial
Ir a siguiente O(1) Trivial
Buscar O(lg n) Búsqueda binaria
Insertar O(n) Búsqueda secuencial con desplazamiento
Borrar O(n) Desplazamiento
Reordenar O(n lg n) caso promedio
O(n2) peor caso
Ordenación rápida (Quicksort)
OperacionesOrden asintóticoAlgoritmo
Inicializar O(1) Trivial
Destruir O(n) Borrado de nodos
Lista llena O(1) Trivial
Elemento actual O(1) Trivial
Ir a inicio O(1) Trivial
Ir a siguiente O(1) Trivial
Buscar O(n) Búsqueda secuencial
Insertar O(n) Búsqueda secuencial e inserción
Borrar O(1) Trivial
Reordenar O(n lg n) Ordenación por fusión recursiva adaptada a listas

En las tablas anteriores, el valor n representa el número de elementos almacenados en ese momento en la lista.

 

4. Programas de ejemplo que usan el TAD