Menu
Coddy logo textTech

Lista doblemente enlazada

Última actualización

Una lista doblemente enlazada es una lista enlazada donde cada nodo tiene dos punteros: next (al nodo siguiente) y prev (al anterior). Ese enlace hacia atrás adicional permite recorrer en ambas direcciones y eliminar un nodo en O(1) cuando ya tienes una referencia a él, porque puedes llegar directamente a su predecesor en lugar de recorrer desde la cabeza. Pulsa reproducir arriba para ver cómo los nodos se enlazan y reenlazan en ambos sentidos.

El coste es un puntero adicional por nodo y más gestión: cada inserción y eliminación debe actualizar tanto next como prev en los vecinos. Es la estructura detrás de muchas colas dobles (deques) y cachés LRU, donde importa la eliminación rápida por ambos extremos.

Complejidad temporal

OperaciónComplejidadNotas
Insertar en cabeza/colaO(1)Con punteros a cabeza y cola
Eliminar un nodo conocidoO(1)Se llega a prev directamente, sin recorrido
BúsquedaO(n)Sigue siendo un escaneo lineal
Acceso por índiceO(n)Sin acceso aleatorio

Lista simplemente enlazada vs doblemente enlazada

AspectoSimpleDoble
Punteros por nodo1 (next)2 (next + prev)
Recorrer hacia atrásNo
Eliminar un nodo conocidoO(n) (buscar prev)O(1)
Sobrecarga de memoriaMenorMayor

Ejemplo resuelto

Construyendo [10, 20, 30] añadiendo al final y luego eliminando el nodo 20:

PasoEstructuraAcción
InicionullLista vacía: head y tail son ambos null
Añadir 1010Primer nodo; head y tail apuntan a él, prev = next = null
Añadir 2010 <-> 20Se asigna 10.next = 20 y 20.prev = 10; tail = 20
Añadir 3010 <-> 20 <-> 30Se asigna 20.next = 30 y 30.prev = 20; tail = 30
Eliminar 2010 <-> 30Usando 20.prev y 20.next: se asigna 10.next = 30 y 30.prev = 10 en O(1)

Cuándo usar una lista doblemente enlazada

Úsala cuandoEvítala cuando
Necesitas recorrer o empalmar en ambas direccionesSolo avanzas hacia adelante: una lista simple es más ligera
Eliminas nodos arbitrarios de los que ya tienes referencia (O(1))Sueles indexar por posición: usa un array para acceso O(1)
Implementas un deque, una caché LRU o un historial de deshacerLa memoria es escasa: el puntero prev adicional duplica la sobrecarga de enlaces
Las inserciones y eliminaciones ocurren a menudo en ambos extremosLos datos son pequeños y cambian poco: copiar arrays es más barato

Código de Doubly Linked List

Una implementación limpia y ejecutable de Doubly Linked List en Python, JavaScript, Java, C++, C. Elige un lenguaje, copia el código o ábrelo ya cargado en el Playground de Coddy.

Código de Doubly Linked List en Python

Python
1class Node:2    def __init__(self, value):3        self.value = value4        self.prev = None5        self.next = None6
7
8class DoublyLinkedList:9    def __init__(self):10        self.head = None11        self.tail = None12
13    def append(self, value):14        node = Node(value)15        if self.tail is None:16            self.head = self.tail = node17            return18        # Wire both directions: old tail <-> new node19        node.prev = self.tail20        self.tail.next = node21        self.tail = node22
23    def prepend(self, value):24        node = Node(value)25        if self.head is None:26            self.head = self.tail = node27            return28        node.next = self.head29        self.head.prev = node30        self.head = node31
32    def forward(self):33        values, current = [], self.head34        while current:35            values.append(current.value)36            current = current.next37        return values38
39    def backward(self):40        values, current = [], self.tail41        while current:42            values.append(current.value)43            current = current.prev44        return values45
46
47lst = DoublyLinkedList()48for value in [2, 3, 4]:49    lst.append(value)50lst.prepend(1)51
52print("Forward: ", lst.forward())53print("Backward:", lst.backward())
Ejecuta este código en el Playground de Python

Preguntas frecuentes sobre listas doblemente enlazadas

¿Cuál es la diferencia entre una lista simplemente enlazada y una doblemente enlazada?
Una lista simplemente enlazada tiene un puntero por nodo (next), así que solo puedes avanzar. Una lista doblemente enlazada añade un puntero prev, lo que permite recorrer hacia atrás y eliminar un nodo del que tienes una referencia en O(1), a cambio de un puntero adicional por nodo y de actualizar dos enlaces en cada cambio.
¿Cuándo compensa una lista doblemente enlazada la memoria adicional?
Cuando necesitas recorrido hacia atrás o eliminación en O(1) de nodos arbitrarios que ya referencias: los casos clásicos son las colas dobles (deques) y las cachés LRU, donde las entradas se mueven y expulsan por ambos extremos con frecuencia.
¿Por qué una lista doblemente enlazada puede eliminar un nodo en O(1)?
Para eliminar un nodo hay que conectar su predecesor con su sucesor. En una lista simplemente enlazada tendrías que recorrer desde la cabeza para encontrar el predecesor (O(n)); en una lista doblemente enlazada el puntero prev del nodo te da el predecesor directamente, así que la reconexión es O(1).
Lista doblemente enlazada vs array: ¿cuál debería usar?
Usa un array cuando necesitas acceso O(1) por índice e iteración eficiente en caché, y cuando las inserciones ocurren sobre todo al final. Usa una lista doblemente enlazada cuando insertas o eliminas con frecuencia en el medio o en ambos extremos con una referencia a nodo, ya que eso es O(1) frente al desplazamiento O(n) de un array. Los arrays ganan en memoria y localidad; la lista gana en ediciones estructurales.
¿Qué es un nodo centinela en una lista doblemente enlazada?
Un nodo centinela (o ficticio) es un marcador que se sitúa antes de la cabeza o después de la cola para que la lista nunca esté realmente vacía. Elimina las comprobaciones de null para head, tail y las inserciones/eliminaciones en los límites, permitiendo que toda operación siga el mismo camino de reconexión. Muchas implementaciones de cachés LRU en producción usan dos centinelas para no tratar los extremos como casos especiales.
¿Cuál es el error más común al eliminar de una lista doblemente enlazada?
Olvidar actualizar head o tail al eliminar el primer o último nodo, lo que deja un puntero colgante a un nodo liberado. Comprueba siempre si node.prev es null (actualiza head) o si node.next es null (actualiza tail) antes de reconectar los vecinos.
Coddy programming languages illustration

Domina los algoritmos con Coddy

COMENZAR