Fundamentos de Programación Cap 5 y Cap 6 Heileman, Gregory
Fundamentos de Programación Cap 5 y Cap 6 Heileman, Gregory
Fundamentos de Programación Cap 5 y Cap 6 Heileman, Gregory
LISTAS
Las listas son una estructura de datos más fundamentales de entre las empleadas para almacenar
una colección de elementos. La importancia del TAD Lista reside en que puede usarse para
implementar una amplia variedad de otros TADs.
Una lista puede definirse como una n-tupla dinámica ordenada, el término de “dinámica”
en esta definición se justifica con el fin de resaltar que los elementos en esta n-tupla pueden
cambiar con el tiempo.
El primer elemento de la lista, se denomina “CABEZA” de la lista, mientras que el último
elemento, se conoce como la “COLA” de la lista. El número de elementos de una lista se refiere a
la longitud de la lista.
Si todos los elementos almacenados de una lista son del mismo tipo, entonces se dice que
la lista es “HOMOGENEA”. Si distintos tipos de elementos están almacenados en la lista, entonces
la lista se dice que es “HETEROGENEA”.
A continuación, se ofrecen las operaciones que definiremos para acceder a los elementos
de las listas:
Las operaciones Insertar, Añadir, Eliminar, Inicio y Siguiente modifican las listas a las
que son aplicadas. El resto de las operaciones simplemente consultan las listas con el
fin de obtener información acerca de ellas.
Se asume que una lista tiene una “VARIABLE DE POSICIÓN” actual que se refiere a cierto
elemento de la lista. Esta variable puede usarse para iterar sobre los elementos de una lista.
Si todos los elementos que forman una estructura de datos dada están almacenados uno
detrás de otro en posiciones de memoria consecutivas, decimos que la estructura de datos tiene
“DISPOSICIÓN SECUENCIAL” en la memoria de la computadora. La “DISPOSICIÓN SECUENCIAL”
hace posible acceder a cualquier elemento de la estructura de datos en tiempo constante. Dada la
dirección de comienzo de la estructura de datos en memoria, podemos encontrar la dirección de
cualquier elemento de la estructura de datos simplemente calculando su desplazamiento a partir
de la dirección de comienzo. Un “ARRAY” es un ejemplo de estructura de datos con “DISPOSICIÓN
SECUENCIAL”, debido a que se tarda la misma cantidad de tiempo en acceder al cualquier
elemento, una estructura de datos con “DISPOSICIÓN SECUENCIAL” también se denomina una
“ESTRUCTURA DE DATOS DE ACCESO DIRECTO”.
El TAD Lista puede ser implementado usando “DISPOSICIÓN SECUENCIAL” si se asigna en
tiempo de compilación un array de posiciones de memoria que sea suficientemente grande para
mantener todos los elementos de la lista. Las ventajas ofrecidas por este enfoque incluyen su
simplicidad, así como la eficiencia con la que las operaciones del TAD Lista pueden ser
implementadas. La principal desventaja que resulta de asignar el array en tiempo de compilación
es que debe establecerse un límite a priori sobre el número de elementos que pueden ser
almacenados en las listas. Esto puede conducir a problemas en tiempo de ejecución.
Antes de comentar una estrategia común para asignar más memoria, definimos primero el
“FACTOR DE CARGA” de un array como el número de elementos almacenados en el array, dividido
por el tamaño del array. Basándonos en esta definición, la estrategia es como sigue: Cuando el
factor de carga alcance 1, asignar dinámicamente un nuevo array cuyo tamaño sea el doble del
tamaño del array actual, entonces copiar todos los elementos almacenados en el array actual en el
nuevo array.
Clases iteradoras: Resulta útil abstraer los aspectos de control de un tipo de datos. Esto
habitualmente se conseguirán suministrando un iterador con una implementación de un tipo de
datos. Un “ITERADOR” encarna la abstracción del control en la secuenciación de los elementos de
un tipo de datos. Esto nos permite mantener una visión abstracta del flujo de control en nuestras
implementaciones de tipos de datos.
Para la operación Obtener se tendrá que buscar en toda la lista antes de que se encuentre
el elemento deseado. También tendrá que buscarse en la lista entera con el fin de determinar que
un elemento no está en la lista. Si la lista contiene n elementos, la operación Buscar requiere
tiempo utilizando la implementación dada, este planteamiento de fuerza bruta se conoce como
“BÚSQUEDA LINEAL O SECUENCIAL”.
Búsqueda Binaria: Una búsqueda binaria comienza comparando el elemento central de la
lista ordenada con la clave de búsqueda. Esto divide efectivamente la lista en dos partes, una
mitad inferior y una mitad superior. Como la lista está ordenada, la clave de cada elemento de la
mitad inferior de la lista debe ser menor que la clave de cada elemento de la mitad superior de la
lista. Si la clave de búsqueda es igual a la clave del elemento central, entonces hemos encontrado
el elemento deseado y la búsqueda termina. Sin embargo, si la clave de búsqueda es menor que la
clave del elemento central, entonces se examina el elemento central de la mitad inferior de la
lista. En otro caso, la clave de búsqueda debe ser mayor que la clave del elemento central, y se
examina el elemento central de la mitad superior de la lista. La lista continúa dividiéndose de esta
forma hasta que, o bien se encuentra el elemento deseado, o bien se ha buscado en toda la lista.
La operación Insertar del TAD conjunto dinámico puede ser implementada en tiempo si
no nos preocupamos de mantener la lista ordenada y el array es suficientemente grande como
para almacenar el nuevo elemento. Simplemente utilizamos la operación Añadir de la TAD Lista
para incorporar cada elemento a la cola de la lista, si se utiliza la técnica de la búsqueda binaria
para la operación Buscar, entonces el orden de la lista debe ser preservado después de la
inserción de cada nuevo elemento. La operación Eliminar también requerirá tiempo, dado que le
elemento que queremos eliminar debe ser encontrado, y en el caso peor se encuentra en la
cabeza de la lista.
Es otro planteamiento para implementar el TAD Lista, asigna memoria para almacenar los
elementos de la lista conforme se necesita durante la ejecución, y conecta los elementos de la lista
usando punteros. La memoria es desasignada cuando ya no se necesita más un elemento de la
lista. Una lista enlazada se representa por la secuencia de nodos conectados por enlaces.
Lista simplemente enlazada: Debido a que cada nodo de la lista está conectado al
siguiente por un solo enlace. El nodo contiene dos campos datos (contiene un elemento de la
lista) y siguiente (almacena un enlace al siguiente nodo de la lista).
Lista doblemente enlazada: Cada nodo en una lista doblemente enlazada contiene tres
campos un campo almacena un elemento de la lista y los otros dos almacenan enlaces a los
nodos precedente y siguiente de la lista, en este caso se usan punteros nulos para marcar ambos
extremos de la lista.
Lista enlazada circular: En lugar de colocar el puntero nulo en el campo siguiente del nodo
cola, almacenamos un puntero a la cabeza de la lista.
Lista doblemente enlazada circular: Necesitaríamos almacenar un puntero al nodo cola en
el campo anterior del nodo cabeza.
A menudo se añaden nodos mudos denominados “Centinelas” para enlazar listas, estos
pueden utilizarse para almacenar información acerca de una lista, o para simplificar la
comprobación de condiciones de límite en una lista.
Una matriz dispersa contiene relativamente pocos elementos no nulos. Así la mayoría del
almacenamiento en este caso está ocupada por elementos 0.
El operador (-) se sobre carga dos veces, una para el vector negativo y otra para la resta
entre vectores.
El operador (+) se sobre carga para realizar la suma de vectores.
El operados (*) se sobre carga tres veces, la primera se utiliza cuando queremos
multiplicar un vector por un escalar, la segunda se utiliza para calcular el producto escalar de dos
vectores y la tercera se utiliza para calcular el producto de un vector por una matriz.
Capítulo 6
PILAS Y COLAS
FIFO: Es una estructura en la que el primero que entra, es el primero que sale; lo que significa que
el primer elemento almacenado en este tipo será el primer elemento obtenido de ella. (Ejemplo
Cola).
LIFO: Es una estructura en la que el último que entra, es el primero que sale; lo que significa que el
último elemento que es almacenado en la estructura será el primer elemento obtenido de ella.
(Ejemplo Pila).
En cada operación TAD cola, “x” de nuevo representa a un elemento y “Q” a una cola
arbitraria.
Operación Añadir(Q,x): Inserta x en Q.
Operación Primero(Q): Devuelve el elemento que lleva más tiempo en Q.
Operación Avanzar(Q): Elimina el elemento que lleva más tiempo en Q.