Menu
Coddy logo textTech

Lista duplamente ligada

Última atualização

Uma lista duplamente ligada é uma lista ligada em que cada nó guarda dois ponteiros: next (para o nó seguinte) e prev (para o anterior). Esse elo para trás adicional permite percorrer em ambas as direções e remover um nó em O(1) quando você já tem uma referência a ele, porque é possível alcançar o predecessor diretamente em vez de caminhar desde a cabeça. Pressione reproduzir acima para ver os nós ligarem e religarem nos dois sentidos.

O custo é um ponteiro adicional por nó e mais gestão: cada inserção e remoção deve atualizar tanto next quanto prev nos vizinhos. É a estrutura por trás de muitas filas duplas (deques) e caches LRU, onde a remoção rápida por ambas as extremidades importa.

Complexidade temporal

OperaçãoComplexidadeNotas
Inserir na cabeça/caudaO(1)Com ponteiros para cabeça e cauda
Remover um nó conhecidoO(1)Alcança prev diretamente, sem percorrer
BuscaO(n)Ainda é uma varredura linear
Acesso por índiceO(n)Sem acesso aleatório

Lista simplesmente ligada vs duplamente ligada

AspectoSimplesDupla
Ponteiros por nó1 (next)2 (next + prev)
Percorrer para trásNãoSim
Remover um nó conhecidoO(n) (achar prev)O(1)
Sobrecarga de memóriaMenorMaior

Exemplo resolvido

Construindo [10, 20, 30] acrescentando ao final e depois removendo o nó 20:

PassoEstruturaAção
InícionullLista vazia: head e tail são ambos null
Acrescentar 1010Primeiro nó; head e tail apontam para ele, prev = next = null
Acrescentar 2010 <-> 20Define 10.next = 20 e 20.prev = 10; tail = 20
Acrescentar 3010 <-> 20 <-> 30Define 20.next = 30 e 30.prev = 20; tail = 30
Remover 2010 <-> 30Usando 20.prev e 20.next: define 10.next = 30 e 30.prev = 10 em O(1)

Quando usar uma lista duplamente ligada

Use quandoEvite quando
Você precisa percorrer ou emendar em ambas as direçõesVocê só avança para frente: uma lista simples é mais leve
Você remove nós arbitrários dos quais já tem referência (O(1))Você geralmente indexa por posição: use um array para acesso O(1)
Você implementa um deque, cache LRU ou histórico de desfazerA memória é escassa: o ponteiro prev adicional dobra a sobrecarga de elos
Inserções e remoções ocorrem com frequência em ambas as extremidadesOs dados são pequenos e mudam pouco: copiar arrays é mais barato

Código de Doubly Linked List

Uma implementação limpa e executável de Doubly Linked List em Python, JavaScript, Java, C++, C. Escolha uma linguagem, copie o código ou abra-o já carregado no Playground da Coddy.

Código de Doubly Linked List em 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())
Execute este código no Playground de Python

Perguntas frequentes sobre listas duplamente ligadas

Qual é a diferença entre uma lista simplesmente ligada e uma duplamente ligada?
Uma lista simplesmente ligada tem um ponteiro por nó (next), então você só pode avançar. Uma lista duplamente ligada adiciona um ponteiro prev, permitindo percorrer para trás e remover um nó do qual você tem referência em O(1), ao custo de um ponteiro adicional por nó e de atualizar dois elos a cada mudança.
Quando uma lista duplamente ligada compensa a memória adicional?
Quando você precisa de travessia para trás ou remoção em O(1) de nós arbitrários que já referencia: os casos clássicos são filas duplas (deques) e caches LRU, onde as entradas são movidas e removidas por ambas as extremidades com frequência.
Por que uma lista duplamente ligada consegue remover um nó em O(1)?
Para remover um nó é preciso conectar seu predecessor ao seu sucessor. Em uma lista simplesmente ligada você teria que percorrer desde a cabeça para achar o predecessor (O(n)); em uma lista duplamente ligada o ponteiro prev do nó dá o predecessor diretamente, então a reconexão é O(1).
Lista duplamente ligada vs array: qual devo usar?
Use um array quando precisa de acesso O(1) por índice e iteração eficiente em cache, e quando as inserções ocorrem principalmente no final. Use uma lista duplamente ligada quando insere ou remove com frequência no meio ou nas duas extremidades com uma referência de nó, pois isso é O(1) versus o deslocamento O(n) de um array. Arrays vencem em memória e localidade; a lista vence em edições estruturais.
O que é um nó sentinela em uma lista duplamente ligada?
Um nó sentinela (ou fictício) é um marcador que fica antes da cabeça e/ou depois da cauda para que a lista nunca esteja de fato vazia. Ele elimina as verificações de null para head, tail e as inserções/remoções nas bordas, deixando toda operação seguir o mesmo caminho de reconexão. Muitas implementações de cache LRU em produção usam dois sentinelas para não tratar as extremidades como casos especiais.
Qual é o erro mais comum ao remover de uma lista duplamente ligada?
Esquecer de atualizar head ou tail ao remover o primeiro ou o último nó, o que deixa um ponteiro pendente para um nó liberado. Verifique sempre se node.prev é null (atualize head) ou se node.next é null (atualize tail) antes de reconectar os vizinhos.
Coddy programming languages illustration

Domine algoritmos com a Coddy

COMEÇAR