You are on page 1of 17

LISTAS ENLAZADAS

1) INTRODUCCION

Una lista enlazada es una de las estructuras de datos dinmicas fundamentales,


y puede ser usada para implementar otras estructuras de datos.

Consiste en una secuencia de nodos, en los que se guardan campos de datos


arbitrarios y una o dos referencias (punteros) al nodo anterior o posterior.

El principal beneficio de las listas enlazadas respecto a los arreglos


convencionales es que el orden de los elementos enlazados puede ser diferente
al orden de almacenamiento en la memoria o el disco, permitiendo que el orden
de recorrido de la lista sea diferente al de almacenamiento.

Una lista enlazada es un tipo de dato auto-referenciado porque contienen un


puntero o link a otro dato del mismo tipo.

Las listas enlazadas permiten inserciones y eliminacin de nodos en cualquier


punto de la lista en tiempo constante (suponiendo que dicho punto est
previamente identificado o localizado), pero no permiten un acceso aleatorio.

Existen diferentes tipos de listas enlazadas: Lista Enlazadas Simples, Listas


Doblemente Enlazadas, Listas Enlazadas Circulares y Listas Enlazadas
Doblemente Circulares.
Las listas enlazadas pueden ser implementadas en muchos lenguajes.
Lenguajes tales como Lisp y Scheme tiene estructuras de datos ya construidas,
junto con operaciones para acceder a las listas enlazadas. Lenguajes
imperativos u orientados a objetos tales como C o C++ y Java,
respectivamente, disponen de referencias para crear listas enlazadas.

2) Tipos de Listas Enlazadas


2.1 Listas enlazadas lineales

2.1.1 Listas simples enlazadas

2.1.2 Lista Doblemente Enlazada

2.2 Listas enlazadas circulares

2.2.1 Listas enlazadas circulares simples

2.2.2 Lista Enlazada Doblemente Circular

2.3 Nodos Centinelas

Listas enlazadas lineales:

Listas simples enlazadas

La lista enlazada bsica es la lista enlazada simple la cual tiene un enlace por nodo.
Este enlace apunta al siguiente nodo en la lista, o al valor NULL o a la lista vaca, si
es el ltimo nodo.
Una lista enlazada simple contiene dos valores: el valor actual del nodo y un enlace
al siguiente nodo

Lista Doblemente Enlazada

Un tipo de lista enlazada ms sofisticado es la lista doblemente enlazada o lista


enlazadas de dos vas. Cada nodo tiene dos enlaces: uno apunta al nodo anterior, o
apunta al valor NULL si es el primer nodo; y otro que apunta al nodo siguiente, o
apunta al valor NULL si es el ltimo nodo.

Una lista doblemente enlazada contiene tres valores: el valor, el link al nodo
siguiente, y el link al anterior

En algn lenguaje de muy bajo nivel, XOR-Linking ofrece una va para implementar
listas doblemente enlazadas, usando una sola palabra para ambos enlaces, aunque el
uso de esta tcnica no se suele utilizar.

Listas enlazadas circulares:

En una lista enlazada circular, el primer y el ltimo nodo estn unidos juntos. Esto se
puede hacer tanto para listas enlazadas simples como para las doblemente enlazadas.
Para recorrer una lista enlazada circular podemos empezar por cualquier nodo y
seguir la lista en cualquier direccin hasta que se regrese hasta el nodo original.
Desde otro punto de vista, las listas enlazadas circulares pueden ser vistas como listas
sin comienzo ni fin. Este tipo de listas es el ms usado para dirigir buffers para
ingerir datos, y para visitar todos los nodos de una lista a partir de uno dado.

Una lista enlazada circular que contiene tres valores enteros

Listas enlazadas circulares simples

Cada nodo tiene un enlace, similar al de las listas enlazadas simples, excepto que el
siguiente nodo del ltimo apunta al primero. Como en una lista enlazada simple, los
nuevos nodos pueden ser solo eficientemente insertados despus de uno que ya
tengamos referenciado. Por esta razn, es usual quedarse con una referencia
solamente al ltimo elemento en una lista enlazada circular simple, esto nos permite
rpidas inserciones al principio, y tambin permite accesos al primer nodo desde el
puntero del ltimo nodo. 1

Lista Enlazada Doblemente Circular

En una lista enlazada doblemente circular, cada nodo tiene dos enlaces, similares a
los de la lista doblemente enlazada, excepto que el enlace anterior del primer nodo
apunta al ltimo y el enlace siguiente del ltimo nodo, apunta al primero. Como en
una lista doblemente enlazada, las inserciones y eliminaciones pueden ser hechas
desde cualquier punto con acceso a algn nodo cercano. Aunque estructuralmente una
lista circular doblemente enlazada no tiene ni principio ni fin, un puntero de acceso
externo puede establecer el nodo apuntado que est en la cabeza o al nodo cola, y as
mantener el orden tan bien como en una lista doblemente enlazada.

Nodos Centinelas

A veces las listas enlazadas tienen un nodo centinela (tambin llamado falso nodo o
nodo ficticio) al principio o al final de la lista, el cual no es usado para guardar datos.
Su propsito es simplificar o agilizar algunas operaciones, asegurando que cualquier
nodo tiene otro anterior o posterior, y que toda la lista (incluso alguna que no
contenga datos) siempre tenga un primer y ltimo nodo.

3) Aplicaciones de las listas enlazadas

Las listas enlazadas son usadas como mdulos para otras muchas estructuras de
datos, tales como pilas, colas y sus variaciones.

El campo de datos de un nodo puede ser otra lista enlazada. Mediante este
mecanismo, podemos construir muchas estructuras de datos enlazadas con listas; esta
prctica tiene su origen en el lenguaje de programacin Lisp, donde las listas
enlazadas son una estructura de datos primaria (aunque no la nica), y ahora es una
caracterstica comn en el estilo de programacin funcional.

A veces, las listas enlazadas son usadas para implementar arrays asociativos, y estas
en el contexto de las llamadas listas asociativas. Hay pocas ventajas en este uso de las
listas enlazadas; hay mejores formas de implementar stas estructuras, por ejemplo
con rboles binarios de bsqueda equilibrados. Sin embargo, a veces una lista
enlazada es dinmicamente creada fuera de un subconjunto propio de nodos
semejante a un rbol, y son usadas ms eficientemente para recorrer sta serie de
datos.

4) Ventajas

Como muchas opciones en programacin y desarrollo, no existe un nico mtodo


correcto para resolver un problema. Una estructura de lista enlazada puede trabajar
bien en un caso pero causar problemas en otros. He aqu una lista con algunas de las
ventajas ms comunes que implican las estructuras de tipo lista. En general, teniendo
una coleccin dinmica donde los elementos estn siendo aadidos y eliminados
frecuentemente e importa la localizacin de los nuevos elementos introducidos se
incrementa el beneficio de las listas enlazadas.

Listas Enlazadas vs. Vectores o Matrices

Las listas enlazadas poseen muchas ventajas sobre los arrays:

Los elementos se pueden insertar en una lista indefinidamente mientras que un


array tarde o temprano se llenar necesitar ser redimensionado, una costosa
operacin que incluso puede no ser posible si la memoria se encuentra
fragmentada.

En algunos casos se pueden lograr ahorros de memoria almacenando la misma


cola de elementos entre dos o ms listas es decir, la lista acaba en la misma
secuencia de elementos. De este modo, uno puede aadir nuevos elementos al
frente de la lista manteniendo una referencia tanto al nuevo como a los viejos
elementos - un ejemplo simple de una estructura de datos persistente.

Por otra parte, los arrays permiten acceso aleatorio mientras que las listas
enlazadas slo permiten acceso secuencial a los elementos. Las listas
enlazadas simples, de hecho, solo pueden ser recorridas en una direccin. Esto
hace que las listas sean inadecuadas para aquellos casos en los que es til
buscar un elemento por su ndice rpidamente, como el heapsort. El acceso
secuencial en los arrays tambin es ms rpido que en las listas enlazadas.

Otra desventaja de las listas enlazadas es el almacenamiento extra necesario


para las referencias, que a menudos las hacen poco prcticas para listas de
pequeos datos como caracteres o valores booleanos.

Tambin puede resultar lento y abusivo el asignar memoria para cada nuevo
elemento. Existe una variedad de listas enlazadas que contemplan los
problemas anteriores para resolver los mismos.

Un buen ejemplo que muestra los pros y contras del uso de arrays sobre listas
enlazadas es la implementacin de un programa que resuelva el problema de
Josephus. Este problema consiste en un grupo de personas dispuestas en forma
de crculo. Se empieza a partir de una persona predeterminadas y se cuenta n
veces, la persona n-sima se saca del crculo y se vuelve a cerrar el grupo. Este
proceso se repite hasta que queda una sola persona, que es la que gana. Este
ejemplo muestra las fuerzas y debilidades de las listas enlazadas frente a los
arrays, ya que viendo a la gente como nodos conectados entre s en una lista
circular se observa cmo es ms fcil suprimir estos nodos. Sin embargo, se ve
como la lista perder utilidad cuando haya que encontrar a la siguiente persona
a borrar. Por otro lado, en un array el suprimir los nodos ser costoso ya que no
se puede quitar un elemento sin reorganizar el resto. Pero en la bsqueda de la
n-sima persona tan slo basta con indicar el ndice n para acceder a l
resultando mucho ms eficiente.

Doblemente Enlazadas vs. Simples Enlazadas

Las listas doblemente enlazadas requieren ms espacio por nodo y sus operaciones
bsicas resultan ms costosas pero ofrecen una mayor facilidad para manipular ya
que permiten el acceso secuencial a lista en ambas direcciones. En particular, uno
puede insertar o borrar un nodo en un nmero fijo de operaciones dando nicamente
la direccin de dicho nodo (Las listas simples requieren la direccin del nodo anterior
para insertar o suprimir correctamente). Algunos algoritmos requieren el acceso en
ambas direcciones.

Circulares Enlazadas vs. Lineales Enlazadas

Las listas circulares son ms tiles para describir estructuras circulares y tienen la
ventaja de poder recorrer la lista desde cualquier punto. Tambin permiten el acceso
rpido al primer y ltimo elemento por medio de un puntero simple.

Nodos Centinelas (header nodes)

La bsqueda comn y los algoritmos de ordenacin son menos complicados si se


usan los llamados Nodos Centinelas o Nodos Ficticios, donde cada elemento apunta a
otro elemento y nunca a nulo. El Nodo Centinela o Puntero Cabeza contienen, como
otro, un puntero siguiente que apunta al que se considera como primer elemento de la
lista. Tambin contiene un puntero previo que hace lo mismo con el ltimo elemento.
El Nodo Centinela es definido como otro nodo en una lista doblemente enlazada, la
asignacin del puntero frente no es necesaria y los punteros anterior y siguiente
estarn apuntando a s mismo en ese momento. Si los punteros anterior y siguiente
apuntan al Nodo Centinela la lista se considera vaca. En otro caso, si a la lista se le
aaden elementos ambos punteros apuntarn a otros nodos. Estos Nodos Centinelas
simplifican muchos las operaciones pero hay que asegurarse de que los punteros
anterior y siguiente existen en cada momento. Como ventaja eliminan la necesidad de
guardar la referencia al puntero del principio de la lista y la posibilidad de
asignaciones accidentales. Por el contrario, usan demasiado almacenamiento extra y
resultan complicados en algunas operaciones.

Listas enlazadas usando Arrays de Nodos

Los lenguajes que no aceptan cualquier tipo de referencia pueden crear uniones reemplazando los
punteros por ndices de un array. La ventaja es de mantener un array de entradas, donde cada
entrada tiene campos enteros indicando el ndice del siguiente elemento del array. Pueden haber
nodos sin usarse. Si no hay suficiente espacio, pueden usarse arrays paralelos.

Entonces una lista enlazada puede ser construida, creado un array con esta estructura, y una variable
entera para almacenar el ndice del primer elemento. (ver en la seccin de implementaciones).

Las utilidades de esta propuesta son:


La lista enlazada puede ser movida sobre la memoria y tambin ser rpidamente serializada
para almacenarla en un disco o transferirla sobre una red.

Especialmente para una lista pequea, los arrays indexados pueden ocupar mucho menos
espacio que un conjunto de punteros.

La localidad de referencia puede ser mejorada guardando los nodos juntos en memoria y
siendo reordenados peridicamente.

Algunas desventajas son:

Incrementa la complejidad de la implementacin.

Usar un fondo general de memoria deja ms memoria para otros datos si la lista es ms
pequea de lo esperado si muchos nodos son liberados.

El crecimiento de un array cuando est lleno no puede darse lugar (o habra que
redimensionarlo) mientras que encontrar espacio para un nuevo nodo en una lista resulta
posible y ms fcil.

Por estas razones, la propuesta se usa principalmente para lenguajes que no soportan asignacin de
memoria dinmica. Estas desventajas se atenan tambin si el tamao mximo de la lista se conoce
en el momento en el que el array se crea.

Lenguajes soportados
Muchos lenguajes de programacin tales como Lisp y Scheme tienen listas enlazadas simples ya
construidas. En muchos lenguajes de programacin, estas listas estn construidas por nodos, cada
uno llamado cons o celda cons. Las celdas cons tienen dos campos: el car, una referencia del dato al
nodo, y el cdr, una referencia al siguiente nodo. Aunque las celdas cons pueden ser usadas para
construir otras estructuras de datos, este es su principal objetivo.

En lenguajes que soportan tipos abstractos de datos o plantillas, las listas enlazadas ADTs o
plantillas estn disponibles para construir listas enlazadas. En otros lenguajes, las listas enlazadas
son tpicamente construidas usando referencias junto con el tipo de dato record.

En la seccin de implementaciones hay un ejemplo completo en C y en Maude

Almacenamiento interno y externo


Cuando se construye una lista enlazada, nos enfrentamos a la eleccin de si almacenar los datos de
la lista directamente en los nodos enlazados de la lista, llamado almacenamiento interno, o
simplemente almacenar una referencia al dato, llamado almacenamiento externo. El
almacenamiento interno tiene la ventaja de hacer accesos a los datos ms eficientes, requiriendo
menos almacenamiento global, teniendo mejor referencia de localidad, y simplifica la gestin de
memoria para la lista (los datos son alojados y desalojados al mismo tiempo que los nodos de la
lista).

El almacenamiento externo, por otro lado, tiene la ventaja de ser ms genrico, en la misma
estructura de datos y cdigo mquina puede ser usado para una lista enlazada, no importa cul sea
su tamao o los datos. Esto hace que sea ms fcil colocar el mismo dato en mltiples listas
enlazadas. Aunque con el almacenamiento interno los mismos datos pueden ser colocados en
mltiples listas incluyendo mltiples referencias siguientes en la estructura de datos del nodo, esto
podra ser entonces necesario para crear rutinas separadas para aadir o borrar celdas basadas en
cada campo. Esto es posible creando listas enlazadas de elementos adicionales que usen
almacenamiento interno usando almacenamiento externo, y teniendo las celdas de las listas
enlazadas adicionales almacenadas las referencias a los nodos de las listas enlazadas que contienen
los datos.

En general, si una serie de estructuras de datos necesita ser incluida en mltiples listas enlazadas, el
almacenamiento externo es el mejor enfoque. Si una serie de estructuras de datos necesitan ser
incluidas en una sola lista enlazada, entonces el almacenamiento interno es ligeramente mejor, a no
ser que un paquete genrico de listas genricas que use almacenamiento externo est disponible.
Asimismo, si diferentes series de datos que pueden ser almacenados en la misma estructura de datos
son incluidos en una lista enlazada simple, entonces el almacenamiento interno puede ser mejor.

Otro enfoque que puede ser usado con algunos lenguajes implica tener diferentes estructuras de
datos, pero todas tienen los campos iniciales, incluyendo la siguiente (y anterior si es una lista
doblemente enlazada) referencia en la misma localizacin. Despus de definir estructuras distintas
para cada tipo de dato, una estructura genrica puede ser definida para que contenga la mnima
cantidad de datos compartidos por todas las estructuras y contenidos al principio de las estructuras.
Entonces las rutinas genricas pueden ser creadas usando las mnimas estructuras para llevar a cabo
las operaciones de los tipos de las listas enlazadas, pero separando las rutinas que pueden manejar
los datos especficos. Este enfoque es usado a menudo en rutinas de anlisis de mensajes, donde
varios tipos de mensajes son recibidos, pero todos empiezan con la misma serie de campos,
generalmente incluyendo un campo para el tipo de mensaje. Las rutinas genricas son usadas para
aadir nuevos mensajes a una cola cuando son recibidos, y eliminarlos de la cola en orden para
procesarlos. El campo de tipo de mensaje es usado para llamar a la rutina correcta para procesar el
tipo especfico de mensaje.

En la seccin implementaciones (en este mismo artculo) se expone cdigo referente a este tema.

Hay que notar que cuando usamos almacenamiento externo, se necesita dar un paso extra para
extraer la informacin del nodo y hacer un casting dentro del propio tipo del dato. Esto es porque
ambas listas, de familias y miembros, son almacenadas en dos listas enlazadas usando la misma
estructura de datos (nodo), y este lenguaje no tiene tipos paramtricos.

Si conocemos el nmero de familias a las que un miembro puede pertenecer en tiempo de


compilacin, el almacenamiento interno trabaja mejor. Si, sin embargo, un miembro necesita ser
incluido en un nmero arbitrario de familias, sabiendo el nmero especfico de familias solo en
tiempo de ejecucin, el almacenamiento externo ser necesario.
Agilizacin de la bsqueda
Buscando un elemento especfico en una lista enlazada, incluso si esta es ordenada, normalmente
requieren tiempo O (n) (bsqueda lineal). Esta es una de las principales desventajas de listas
enlazadas respecto a otras estructuras. Adems algunas de las variantes expuestas en la seccin
anterior, hay numerosas vas simples para mejorar el tiempo de bsqueda.

En una lista desordenada, una forma simple para decrementar el tiempo de bsqueda medio es el
mover al frente de forma heurstica, que simplemente mueve un elemento al principio de la lista una
vez que es encontrado. Esta idea, til para crear cachs simples, asegura que el tem usado ms
recientemente es tambin el ms rpido en ser encontrado otra vez.

Otro enfoque comn es indizar una lista enlazada usando una estructura de datos externa ms
eficiente. Por ejemplo, podemos construir un rbol rojo-negro o una tabla hash cuyos elementos
estn referenciados por los nodos de las listas enlazadas. Pueden ser construidos mltiples ndices
en una lista simple. La desventaja es que estos ndices puede necesitar ser actualizados cada vez que
uno nodo es aadido o eliminado (o al menos, antes que el ndice sea utilizado otra vez).

Estructuras de datos relacionadas


Tanto las pilas como las colas son a menudo implementadas usando listas enlazadas, y simplemente
restringiendo el tipo de operaciones que son soportadas.

La skip list, o lista por saltos, es una lista enlazada aumentada con capas de punteros para saltos
rpidos sobre grandes nmeros de elementos, y descendiendo haca la siguiente capa. Este proceso
contina hasta llegar a la capa inferior, la cual es la lista actual.

Un rbol binario puede ser visto como un tipo de lista enlazada donde los elementos estn enlazados
entre ellos mismos de la misma forma. El resultado es que cada nodo puede incluir una referencia al
primer nodo de una o dos listas enlazadas, cada cual con su contenido, formando as los subrboles
bajo el nodo.

Una lista enlazada desenrollada es una lista enlazada cuyos nodos contiene un array de datos. Esto
mejora la ejecucin de la cach, siempre que las listas de elementos estn contiguas en memoria, y
reducen la sobrecarga de la memoria, porque necesitas menos metadatos para guardar cada
elemento de la lista.

Una tabla hash puede usar listas enlazadas para guardar cadenas de tems en la misma posicin de la
tabla hash.

Implementaciones
Operaciones sobre listas enlazadas
Listas Enlazadas Lineales

a) Listas Simples Enlazadas

Nuestra estructura de datos tendr dos campos. Vamos a mantener la variable PrimerNodo que
siempre apunta al primer nodo de tal lista, nulo para la lista vaca.

record Node {
data // El dato almacenado en el nodo
next // Una referencia al nodo siguiente, nulo para el ltimo nodo
}

record List {
Node PrimerNodo //Apunta al primer nodo de la lista; nulo para la lista vaca
}

El recorrido en una lista enlazada es simple, empezamos por el primer nodo y pasamos al siguiente
hasta que la lista llegue al final.

node := list.PrimerNodo
while node not null {
node := node.next
}

El siguiente cdigo inserta un elemento a continuacin de otro en una lista simple. El diagrama
muestra cmo funciona.

function insertAfter(Node node, Node newNode) {


newNode.next := node.next
node.next := newNode///
}

Insertar al principio de una lista requiere una funcin por separado. Se necesita actualizar
PrimerNodo.

function insertBeginning(List list, Node newNode) {


newNode.next := list.firstNode
list.firstNode := newNode
}

De forma similar, tambin tenemos funciones para borrar un nodo dado para borrar un nodo del
principio de la lista. Ver diagrama.
function removeAfter(Node node) {
obsoleteNode := node.next
node.next := node.next.next
destroy obsoleteNode
}
function removeBeginning(List list) {
obsoleteNode := list.firstNode
list.firstNode := list.firstNode.next
destroy obsoleteNode
}

Advertimos que BorrarPrincipio pone PrimerNodo a nulo cuando se borra el ltimo elemento de la
lista. Adjuntar una lista enlazada a otra puede resultar ineficiente a menos que se guarde una
referencia a la cola de la lista, porque si no tendramos que recorrer la lista en orden hasta llegar a la
cola y luego aadir la segunda lista.

b) Listas Doblemente Enlazadas

Con estas listas es necesario actualizar muchos ms punteros pero tambin se necesita menos
informacin porque podemos usar un puntero para recorrer hacia atrs y consultar elementos. Se
crean nuevas operaciones y elimina algunos casos especiales. Aadimos el campo anterior a
nuestros nodos, apuntando al elemento anterior, y UltimoNodo a nuestra estructura, el cual siempre
apunta al ltimo elemento de la lista. PrimerNodo y UltimoNodo siempre estn a nulo en la lista
vaca.

record Node {
data // El dato almacenado en el nodo
next // Una referencia al nodo siguiente, nulo para el ltimo nodo
prev // Una referencia al nodo anterior, nulo para el primer nodo
}
record List {
Node firstNode //apunta al primer nodo de la lista; nulo para la lista vaca
Node lastNode //apunta al ltimo nodo de la lista; nulo para la lista vaca
}

Formas de recorrer la lista:

Hacia Delante

node := list.firstNode
while node null
<do something with node.data>
node := node.next

Hacia Atrs
node := list.lastNode
while node null
<do something with node.data>
node := node.prev

Estas funciones simtricas aaden un nodo despus o antes de uno dado, como el diagrama muestra:

function insertAfter(List list, Node node, Node newNode)


newNode.prev := node
newNode.next := node.next
if node.next = null
node.next := newNode
list.lastNode := newNode
else
node.next.prev := newNode
node.next := newNode

function insertBefore(List list, Node node, Node newNode)


newNode.prev := node.prev
newNode.next := node
if node.prev is null
node.prev := newNode
list.firstNode := newNode
else
node.prev.next := newNode
node.prev := newNode

Tambin necesitamos una funcin para insertar un nodo al comienzo de una lista posiblemente
vaca.

function insertBeginning(List list, Node newNode)


if list.firstNode = null
list.firstNode := newNode
list.lastNode := newNode
newNode.prev := null
newNode.next := null
else
insertBefore (list, list.firstNode, newNode)

Una funcin simtrica que inserta al final:

function insertEnd(List list, Node newNode)


if list.lastNode = null
insertBeginning (list, newNode)
else
insertAfter (list, list.lastNode, newNode)

Borrar un nodo es fcil, solo requiere usar con cuidado firstNode y lastNode.

function remove(List list, Node node)


if node.prev = null
list.firstNode := node.next
else
node.prev.next := node.next
if node.next = null
list.lastNode := node.prev
else
node.next.prev := node.prev
destroy node

Una consecuencia especial de este procedimiento es que borrando el ltimo elemento de una lista se
ponen PrimerNodo y UltimoNodo a nulo, habiendo entonces un problema en una lista que tenga un
nico elemento.

Listas Enlazadas Circulares

Estas pueden ser simples o doblemente enlazadas. En una lista circular todos los nodos estn
enlazados como un crculo, sin usar nulo. Para listas con frente y final (como una cola), se guarda
una referencia al ltimo nodo de la lista. El siguiente nodo despus del ltimo sera el primero de la
lista. Los elementos se pueden aadir por el final y borrarse por el principio en todo momento.
Ambos tipos de listas circulares tienen la ventaja de poderse recorrer completamente empezando
desde cualquier nodo. Esto nos permite normalmente evitar el uso de PrimerNodo y UltimoNodo,
aunque si la lista estuviera vaca necesitaramos un caso especial, como una variable UltimoNodo
que apunte a algn nodo en la lista o nulo si est vaca. Las operaciones para estas listas simplifican
el insertar y borrar nodos en una lista vaca pero introducen casos especiales en la lista vaca.

Listas Enlazadas Doblemente Circulares

Asumiendo que someNodo es algn nodo en una lista no vaca, esta lista presenta el comienzo de
una lista con someNode.

Hacia Delante

node := someNode
do
do something with node.value
node := node.next
while node != someNode

Hacia Atrs

node := someNode
do
do something with node.value
node := node.prev
while node := someNode

Esta funcin inserta un nodo en una lista enlazada doblemente circular despus de un elemento
dado:
function insertAfter(Node node, Node newNode)
newNode.next := node.next
newNode.prev := node
node.next.prev := newNode
node.next := newNode

Para hacer "insertBefore", podemos simplificar "insertAfter (node.prev, newNode)". Insertar un


elemento en una lista que puede estar vaca requiere una funcin especial.

function insertEnd(List list, Node node)


if list.lastNode = null
node.prev := node
node.next := node
else
insertAfter (list.lastNode, node)
list.lastNode := node

Para insertar al principio simplificamos "insertAfter (list.lastNode, node)".

function remove(List list, Node node)


if node.next = node
list.lastNode := null
else
node.next.prev := node.prev
node.prev.next := node.next
if node = list.lastNode
list.lastNode := node.prev;
destroy node

Como una lista doblemente enlazada, "removeAfter" y "removeBefore" puede ser implementada
con "remove (list, node.prev)" y "remove (list, node.next)".

Listas enlazadas usando arrays de nodos

Previamente se crea una estructura que contiene los apuntadores:

record Entry {
integer next; // ndice de la nueva entrada en el array
integer prev; // entrada previa
string name;
real balance;
}

Y finalmente se declara el array: integer listHead;

Entry Records[1000];

Implementacin de una lista enlazada en C


Las listas enlazadas son tpicamente construidas usando referencias junto con el tipo de dato record

#include <stdio.h> /* for printf */


#include <stdlib.h> /* for malloc */

typedef struct ns {
int data;
struct ns *next;
} node;

node *list_add(node **p, int i) {


/* algunos compiladores no requieren un casting del valor del retorno para
malloc */
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p;
*p = n;
n->data = i;
return n;
}

void list_remove(node **p) { /* borrar cabeza*/


if (*p != NULL) {
node *n = *p;
*p = (*p)->next;
free(n);
}
}

node **list_search(node **n, int i) {


while (*n != NULL) {
if ((*n)->data == i) {
return n;
}
n = &(*n)->next;
}
return NULL;
}

void list_print(node *n) {


if (n == NULL) {
printf("lista esta vaca\n");
}
while (n != NULL) {
printf("print %p %p %d\n", n, n->next, n->data);
n = n->next;
}
}

int main(void) {
node *n = NULL;

list_add(&n, 0); /* lista: 0 */


list_add(&n, 1); /* lista: 1 0 */
list_add(&n, 2); /* lista: 2 1 0 */
list_add(&n, 3); /* lista: 3 2 1 0 */
list_add(&n, 4); /* lista: 4 3 2 1 0 */
list_print(n);
list_remove(&n); /* borrar primero(4) */
list_remove(&n->next); /* borrar nuevo segundo (2) */
list_remove(list_search(&n, 1)); /* eliminar la celda que contiene el 1
(primera) */
list_remove(&n->next); /* eliminar segundo nodo del final(0)*/
list_remove(&n); /* eliminar ultimo nodo (3) */
list_print(n);

return 0;
}

You might also like