Beruflich Dokumente
Kultur Dokumente
1 Fundamentos
Las listas son secuencias de elementos, donde estos elementos pueden ser accedidos, insertados o suprimidos en cualquier posicin de la lista. No existe restriccin alguna acerca de la localizacin de esas operaciones. Se trata de estructuras muy flexibles puesto que pueden crecer o acotarse como se quiera. Matemticamente, una lista es una secuencia de cero o ms elementos de un tipo determinado (que por lo general denominaremos !. " menudo se representa una lista como una sucesin de elementos separados por comas#
a(1), a(2), a(3), ... , a(n) donde a $n$ (n %& '! se le llama longitud de la lista. "l suponer n%&(, se dice que a((! es el primer elemento de la lista y a(n! el )ltimo elemento. Si n&', se tiene una lista *ac+a. ,na propiedad importante de una lista es que sus elementos pueden estar ordenados en forma lineal de acuerdo con sus posiciones en la lista. Se dice que a(i! precede a a(i-(!, para i&(,., .., n/(, y que a(i! sucede a a(i/(!, para i&., 0, .., n. ambi1n se dice que el elemento a(i! est en la posicin i de la lista. 2or lo que se *e, las estructuras pila y cola, estudiadas en el cap+tulo anterior, no son ms que casos particulares de la estructura lista generalizada. "l igual que en los casos anteriores, se puede pensar en representar una lista mediante un array unidimensional, lo que permite un acceso eficiente a cada uno de los componentes de la estructura, lo que, en principio, parece proporcionar un esquema adecuado para representar las operaciones que normalmente se desean realizar sobre la lista# acceder a un elemento (nodo! arbitrario de la lista, insertar y borrar nodos, etc. Sin embargo, si bien todas estas consideraciones eran ciertas para las pilas y las colas, cuando se trata de otro tipo de listas, las operaciones a realizar sobre el array resultan bastante ms costosas. 2or e3emplo, supongamos la siguiente lista#
(Antonio, Bartolom, Carlos, David, Emilio, Germn, Jaime, Jos, Luis, anuel) Si se desea a4adir el *alor 56ernando5 a esta lista ordenada de nombres, la operacin se debe realizar en la sexta posicin de la lista, entre los *alores 57milio5 y 58ermn5. 9uando la lista est representada con un array, dic:a insercin implicar tener que desplazar una posicin :acia la derec:a todos los elementos situados ya en la lista a partir de la posicin seis (8ermn,...Manuel!, para de esta forma de3ar una posicin libre en el array y poder insertar all+ el nue*o *alor. 2or otro lado, si suponemos que lo que se desea es borrar de la lista el elemento 59arlos5, de nue*o es necesario desplazar elementos para mantener la estructura secuencial de la lista. 7n este caso es preciso mo*er una posicin :acia la izquierda todos los elementos situados a partir de la cuarta posicin. 9uando el problema es manipular diferentes listas de tama4o *ariable, la representacin secuencial prueba ser, de nue*o, poco apropiada. Si se decide almacenar en distintos arrays cada una de las listas, se tendrn grandes necesidades de almacenamiento. Si, por el contrario, se toma la decisin de usar un )nico array, se necesitar una cantidad muc:o mayor de desplazamientos de informacin. ,na solucin elegante al problema del desplazamiento de informacin en el almacenamiento secuencial se logra mediante la utilizacin de representaciones enlazadas (o ligadas!. " diferencia de la representacin secuencial, en la representacin enlazada los
elementos se pueden situar en cualquier posicin de memoria, y no necesariamente igualmente distantes dentro de ella. ambi1n se puede decir que, si bien en la representacin con arrays el orden de los elementos es el mismo que el orden en la lista, en una representacin enlazada la secuencia de orden de la lista no tiene porque coincidir con la secuencia de almacenamiento en memoria.
1 !! Antonio " 2 !! 3 !! Carlos # !! David % !! & !! $ !! Emilio ' !! " !! Bartolom ... ...
# $
1% 3 ...
9ada elemento de la lista contiene un campo informacin (nombre! ms otro campo que indica en qu1 posicin de memoria se encuentra el siguiente elemento de la lista. "s+, por e3emplo, el primer elemento de la lista ("ntonio! reside en este caso en la posicin (, el segundo (;artolom1! en la <, el tercero (9arlos! en la 0, y as+ sucesi*amente. 7n un lengua3e de programacin, para almacenar la informacin sobre direcciones de *ariables se dispone :abitualmente del tipo de datos puntero. 7ntonces, asociado a la representacin de la informacin de cada nodo :ay que a4adir un campo de tipo puntero que permita ir enlazando correctamente todos los nodos de la lista. 7sto quiere decir que un elemento de la lista tendr ms de un campo de informacin, como m+nimo dos, donde uno (o *arios! de ellos representan informacin que se desea almacenar en la estructura (la *erdaderamente rele*ante para el problema concreto! y otro(s! permite enlazar cada nodo de la lista con otro del mismo tipo. 8racias a la utilizacin de punteros es posible e*itar la relacin expl+cita con las direcciones de memoria. Se traba3a siempre con referencias a elementos no con direcciones espec+ficas, ya que cada *ez que se e3ecute el programa la localizacin real de cada nodo puede cambiar.
7n una representacin enlazada, las estructuras de datos se crean por insercin de nue*os elementos, en este caso no existe un espacio reser*ado globalmente para toda la estructura. 7ntonces, la insercin de un elemento implica realmente que el espacio reser*ado para la estructura aumenta, y que cuando se suprime un nodo, el espacio reser*ado disminuye. 2or esa razn, este tipo de representaciones reciben el nombre de estructuras dinmicas, porque su tama4o cambia durante la e3ecucin del programa adecundose a las necesidades del problema. =eamos con un e3emplo concreto cmo la representacin enlazada de una lista puede facilitar, por e3emplo, la operacin de insercin. =ol*amos a considerar el primer e3emplo tratado en este tema, una lista ordenada de nombres#
(Antonio, Bartolom, Carlos, David, Emilio, Germn, Jaime, Jos, Luis, anuel) donde se desea insertar el nombre 56ernando5. Su posicin correcta dentro de la lista es entre 57milio5 y 58ermn5. 7ntonces, para insertar el nue*o elemento es necesario realizar los siguientes pasos# ((! >eser*ar espacio para almacenar un nue*o nodo de la lista, sea su localizacin x. (.! ?ntroducir en el campo de informacin del nue*o nodo el *alor 56ernando5. (0! @acer que el campo de enlace del nue*o nodo apunte al nodo cuya informacin es 8ermn. (A! @acer que el campo de enlace del nodo cuya informacin es 57milio5 apunte a x. Lo importante es que ya no es necesario mo*er elementos para insertar un nue*o nodo. Se :a sol*entado la necesidad de mo*er informacin a expensas de reser*ar ms espacio en memoria para cada nodo, solamente para almacenar una direccin de memoria, lo cual, en general, resulta ms con*eniente. 2or lo tanto, para :acer posible la representacin enlazada de una estructura de datos es necesario poseer#
/ ,n mecanismo para definir la estructura de un nodo. / ,n m1todo para crear nodos cuando se necesiten. / ,n m1todo para liberar el espacio de un nodo cuando ya no sea necesario.
odas estas capacidades suelen estar disponibles en un lengua3e de alto ni*el, como por e3emplo 2ascal o 9. Mediante los mecanismos de declaracin de tipos de datos, es posible definir la estructura de un nodo y con los procedimientos de manipulacin de datos de tipo puntero es posible crear nue*os nodos (procedimiento 5neB5! y liberar los borrados (procedimiento 5dispose5!. ,n e3emplo de declaracin en 2ascal que permite definir el nodo de una lista general podr+a ser el siguiente#
()*e +alor , -(. in/orma0i1n de 0ada nodo .) (i*o2untero , 3(i*o4odo5 (i*o4odo , re0ord in/orma0ion6 +alor5 enla0e6 (i*o2untero5 end5 Lista , re0ord ini0io6 (i*o2untero5
7n este e3emplo, en el campo 5informacion5 se almacenar la informacin de inter1s asociada con los elementos de la lista (de :ec:o este campo puede ser, a su *ez, un registro!, que es independiente de la estructura de datos, mientras que el campo 5enlace5 es una referencia al siguiente elemento en la secuencia establecida en la lista. Siguiendo con el lengua3e 2ascal, la creacin de un nue*o nodo implica simplemente :acer una llamada al procedimiento 5neB5, pasndole como parmetro una *ariable del tipo 5 ipo2untero5. 7l procedimiento busca un espacio libre en memoria donde almacenar un nodo, cuando lo encuentra le asigna la direccin de inicio del bloque reser*ado a la *ariable que se :a pasado como parmetro, lo que permite el acceso al nodo. Si por el contrario, lo que se desea es liberar el espacio ocupado por un nodo que se :a eliminado de la lista, basta con :acer una llamada al procedimiento 5dispose5, pasando como parmetro el puntero que daba acceso a dic:o nodo. 2ara familiarizarnos con la manipulacin de estructuras enlazadas, *amos a empezar por *er la representacin enlazada de un par de estructuras de datos bien conocidas, las pilas y las colas, para despu1s generalizar los mecanismos de manipulacin a la estructura lista.
Pilas enlazadas
9omenzando por la estructura pila, enlazando los elementos con punteros las operaciones de insercin y borrado resultan muy simples. " continuacin definiremos la estructura pila con esta nue*a representacin.
Crear pila:
Ceclaramos los tipos de datos necesarios para representar un nodo e inicializamos la pila como *acia. ((! Ceclaraciones# 4odo7*ila6 re8istro (in/orma0ion6 (, enla0e6 *untero a 4odo7*ila) 0ima6 *untero a 4odo7*ila (2)Asi8na0i1n de *ila va09a
!peraci"n de inserci"n:
9on la representacin enlazada de la pila, la estructura tiene una menor limitacin en cuanto al posible n)mero de elementos que se pueden almacenar simultneamente. @ay que tener en cuenta que la representacin de la pila ya no requiere la especificacin de un tama4o mximo, por lo que mientras exista memoria disponible se *a a poder reser*ar espacio para nue*os elementos. 2or esa razn, se *a a suponer en el siguiente algoritmo que la condicin de pila llena no se *a a dar y, por lo tanto, no ser necesaria su comprobacin.
l#oritmo
pilar
Entrada =6 ( (. elemento >ue se desea insertar .) ?ni0io * :!! 0rear7es*a0io *3.in/orma0ion :!! = *3.enla0e :!! 0ima 0ima :!! * @in
9omo se puede obser*ar el algoritmo de insercin utilizando esta nue*a representacin continua siendo muy simple, siendo el coste del mismo constante (cuatro pasos!.
!peraci"n de eliminaci"n:
Lo )nico que :ay que tener en cuenta a la :ora de dise4ar un algoritmo para esta operacin es la utilizacin eficiente de la memoria, de forma que el espacio ocupado por el nodo borrado *uel*a a estar disponible para el sistema.
l#oritmo $esapilar
Aalida =6 ( +ariaBle *6 *untero a 4odo7*ila
?ni0io si 2ila7va0ia enton0es CError6 *ila va0iaC sino * :!! 0ima = :!! *3.in/orma0ion 0ima :!! *3.enla0e liBerar7es*a0io(*) /in7sino @in
La solucin dada se puede extender a $m$ pilas, de :ec:o como los enlaces entre elementos son establecidos por el programador, no por el m1todo de representacin, es como si las pilas siempre compartiesen espacios diferentes, no interfieren unas con otras. Se trata de una solucin conceptual y computacionalmente simple. No existe necesidad de desplazar unas pilas para proporcionar ms espacio a otras. 7l incremento de espacio de almacenamiento que implica la representacin enlazada se *e compensada por la capacidad de representacin de listas comple3as de una forma simple y por la disminucin del tiempo de cmputo asociado a la manipulacin de listas, respecto a la representacin secuencial.
Colas enlazadas
"nlogamente al desarrollo :ec:o para las pilas se puede pasar a definir las operaciones requeridas para especificar una cola de forma enlazada.
Crear cola:
Ceclaramos los tipos de datos necesarios para representar un nodo e inicializamos la cola como *acia. ((! Ceclaraciones# 4odo70ola6 re8istro (in/orma0ion6 (, enla0e6 *untero a 4odo70ola) ini0io, /inal6 *untero a 4odo70ola (2)Asi8na0i1n de 0ola va09a ini0io :!! 4;L< /inal :!! 4;L<
Entrada =6 ( +ariaBle *6 *untero a 4odo70ola ?ni0io * :!! 0rear7es*a0io *3.in/orma0ion :!! = *3.enla0e :!! nulo si Cola7va0ia enton0es ini0io :!! * sino /inal3.enla0e :!! * /inal :!! * @in
9rear una lista *ac+a. Ceterminar si la lista est *ac+a. "cceder a un nodo cualquiera de la lista.
Da :emos *isto anteriormente la declaracin general de tipos para un nodo de la lista en 2ascal, es fcil transformar 1sta a cualquier otro lengua3e de programacin que nos interese. 2asemos directamente a la definicin de las operaciones enumeradas. 7s importante tener en cuenta que es necesario declarar una *ariable que permita acceder en todo momento a la estructura a tra*1s del primer elemento de la lista, para a partir de 1l poder recorrer toda la estructura. Llamaremos inicio a dic:a *ariable, concr1tamente al )nico campo de esa *ariable.
l#oritmo %niciarLista
Entrada l6 Lista ?ni0io l.ini0io :!! 4;L< @in
l#oritmo Lista'acia
Entrada l6 Lista Aalida (0ierto, /also) ?ni0io si (l.ini0io , 4;L<) enton0es devolver(0ierto) sino devolver(/also) @in
l#oritmo Localizar
Entradas l6 Lista =6 +alor lo0aliEar .) (. in/orma0i1n >ue se desea
Aalida *6 *untero a nodo Bus0ado .) +ariaBles *6 *untero a nodo ?ni0io * :!! l.ini0io mientras (* :F 4;L<) ) (*3.in/orma0ion :F =) Da0er * :!! *3.enla0e devolver(*) (. si * , 4;L<, enton0es no se Da en0ontrado un nodo 0u)a in/orma0i1n sea = .) @in (. dire00i1n del nodo
La condicin de b)squeda puede cambiar ligeramente pero la estructura del algoritmo se mantiene :abitualmente intacta# buscar secuencialmente :asta que se cumpla la condicin impuesta o se alcance el final de la lista. 7l proceso de b)squeda, tal como se :a planteado resultar+a adecuado para aplicar la estrategia del centinela que ya :emos comentado en *arias ocasiones.
l#oritmo %nsertar$etras
Entradas l6 Lista donde6 *untero a nodo =6 +alor (. in/orma0i1n >ue vamos a insertar .) +ariaBles *6 *untero a nodo ?ni0io 0rear7es*a0io(*) *3.in/orma0ion :!! = si Lista+a0ia enton0es l.ini0io :!! * *3.enla0e :!! 4;L< sino *3.enla0e :!! donde3.enla0e donde3.enla0e :!! *
/in7sino @in
l#oritmo %nsertar$elante
Entradas l6 Lista donde6 *untero a nodo =6 +alor (. in/orma0i1n >ue vamos a insertar .) +ariaBles *6 *untero a nodo ?ni0io 0rear7es*a0io(*) si Lista+a0ia enton0es *3.in/orma0ion :!! = l.ini0io :!! * *3.enla0e :!! 4;L< sino *3 :!! donde3 (. *3.in/orma0ion :!! donde3.in/orma0ion .) (. *3.enla0e :!! donde3.enla0e .) donde3.enla0e :!! * donde3.in/orma0ion :!! = /in7sino @in
La operacin de insercin delante presenta una peque4a dificultad adicional, el sentido de los enlaces dentro de la lista. @ay que tener en cuenta que tal como se :a creado la estructura de la lista, en ella es fcil pasar de un elemento al siguiente dentro de la secuencia, pero no es inmediato pasar al anterior. 2ara ello es necesario *ol*er a recorrer la lista desde el primer elemento :asta alcanzar el deseado. 2or esa razn, en el algoritmo anterior lo que en realidad se :ace es insertar un nodo detrs del apuntado por donde, pero en ese nue*o nodo no se inserta la nue*a informacin sino que se almacena la que finalmente debe quedar detrs (la contenia donde)!, finalmente el *alor x se almacena en la posicin indicada por donde y la informacin queda almacenada en el orden que se deseaba.
l#oritmo &orrar*odo
Entradas l6 Lista donde6 *untero a nodo +ariaBles
*6 *untero a nodo ?ni0io si Lista+a0ia enton0es CError6 lista va0iaC sino si (l.ini0io3.enla0e , 4;L<) enton0es liBerar7es*a0io(l.ini0io) l.ini0io , 4;L< sino si (donde3.enla0e , 4;L<) enton0es * :!! l.ini0io mientras (*3.enla0e3.enla0e :F 4;L<) Da0er * :!! *3.enla0e *3.enla0e :!! 4;L< liBerar7es*a0io(donde) sino * :!! donde3.enla0e donde3 :!! *3 liBerar7es*a0io(*) /in7sino /in7sino /in7sino @in
(. in/orma0i1n de 0ada
(i*o2untero , 3(i*o4odo5 (i*o4odo , re0ord in/orma0ion6 +alor5 si8, ant6 (i*o2untero5 end5 Lista , re0ord ini0io6 (i*o2untero5 end5 +ar l6 ListaD5
":ora, si suponemos que p apunta a un nodo en una lista doblemente enlazada y que la estructura de un nodo tiene la forma anterior, entonces se cumple que# * , *3.ant3.si8 , *3.si83.ant
7sta expresin refle3a la principal *irtud de esta estructura, es igualmente simple mo*erse :acia adelante o :acia atrs en la lista. La especificacin completa de estas listas requiere la definicin de las principales operaciones de manipulacin# insercin y borrado, aunque *eremos primero la operacion de determinacin de una lista *acia y su inicializacin.
l#oritmo %niciarLista
Entrada l6 ListaD +ariaBle *6 *untero a nodo ?ni0io 0rear7es*a0io(*) *3.si8 :!! * *3.ant :!! * l.ini0io :!! * @in
La condicin lista *ac+a a:ora implicar comprobar si el sucesor (o el antecesor! de un nodo es igual a si mismo. 7so slo se cumplir cuando cuando el )nico nodo presente en la estructura sea el que :ace el papel de cabeza.
l#oritmo Lista'acia
Entrada l6 ListaD Aalida
(0ierto, /also) ?ni0io si (l.ini0io , l.ini0io3.si8) enton0es devolver(0ierto) sino devolver(/also) @in
=eamos a:ora como quedar+a el algoritmo de insercin sobre una lista circular doblemente enlazada con nodo cabeza. Se considera el caso en el que es necesario insertar el nue*o nodo detrs de un nodo ya existente. ":ora, la insercin delante del nodo resultar+a completamente anloga.
l#oritmo %nsertar$etras
Entrada l6 ListaD donde6 *untero a nodo =6 +alor +ariaBle *6 *untero a nodo ?ni0io 0rear7es*a0io(*) *3.in/orma0ion :!! = *3.si8 :!! donde3.si8 *3.ant :!! donde donde3.si83.ant :!! * donde3.si8 :!! * @in
9abe destacar que no se da ning)n caso especial y todas las inserciones de nodos se realizan de la misma manera, incluso aunque la lista est1 *ac+a.
l#oritmo &orrar*odo
Entrada l6 ListaD donde6 *untero a nodo ?ni0io si Lista+a0ia enton0es CError6 lista va0iaC sino donde3.ant3.si8 :!! donde3.si8 donde3.si83.ant :!! donde3.ant liBerar7es*a0io(donde) /in7sino @in
7l algoritmo para localizar un elemento dentro de la lista doblemente enlazada es similar al de una lista simple sal*o un detalle. "ntes de recorrer la lista, el nodo auxiliar encargado de ello tendr que apuntar a l.inicio).si#, ya que el nodo cabeza no contiene informacin, slo es un formalismo para simplificar las operaciones de manipulacin.