edubun
Português

Listas encadeadas

Acrescentar um valor na frente de uma lista encadeada muda dois ponteiros, tenha a lista 4 valores ou 4 milhões.

Valores que apontam para o próximo

Um array guarda os valores lado a lado, e é por isso que a frente é cara de mudar. Uma lista encadeada abandona essa regra. Cada valor vive num pequeno registro próprio chamado nó, e os nós podem ficar em qualquer lugar da memória. As notas do 6.006 do MIT descrevem um nó com dois campos: o item e next, um ponteiro para o nó seguinte. A lista em si só lembra o primeiro nó, chamado head (cabeça). O next do último nó é null, o que marca o fim.

Para ler a lista, você começa em head e segue os ponteiros next um por um, como seguir uma série de bilhetes em que cada um diz onde o próximo está escondido. Isso tem um custo. Não existe fórmula para o endereço do quarto nó, então pegar o valor na posição i exige visitar i + 1 nós. O MIT lista get at(i) de uma lista encadeada como O(n), enquanto o array fazia isso em um passo.

// um nó por valor: { value, next }
let head = null;
for (const v of [4, 30, 7, 12]) head = { value: v, next: head };
// percorrer a lista
for (let n = head; n !== null; n = n.next) console.log(n.value); // 12, 7, 30, 4

Mudando a lista religando os nós

A vantagem aparece quando você muda a lista. Para pôr um valor novo na frente, crie um nó cujo next é o head atual e depois aponte head para o nó novo. Duas mudanças de ponteiro, e nada mais se move. Apagar o nó da frente é uma mudança: aponte head para head.next. Compare com o array, em que as mesmas operações moviam todos os valores.

No meio, o trabalho é achar o lugar. Para inserir na posição i, você anda até o nó logo antes dela (i visitas) e depois faz as mesmas duas mudanças de ponteiro: new.next = prev.next, depois prev.next = new. A ordem importa. Se você mudar prev.next primeiro, o resto da lista se perde, porque nada mais aponta para ele. No laboratório, um passo é um nó visitado ou um ponteiro alterado, então inserir na posição 2 de uma lista de 4 nós custa 2 visitas mais 2 mudanças, 4 passos.

Carregando

Arraste para girar. Role ou faça pinça para dar zoom.

Uma lista simplesmente encadeada de quatro nós. Escolha uma posição com o controle deslizante e insira ou apague; o contador separa os nós visitados dos ponteiros alterados. Achar anda a partir de head até encontrar o valor ou null.
OperaçãoArray (n valores)Lista encadeada (n nós)
Pegar o valor na posição i1i + 1 visitas
Inserir na frenten movimentos + 1 escrita2 mudanças de ponteiro
Apagar a frente1 leitura + (n − 1) movimentos1 mudança de ponteiro
Inserir na posição i(n − i) movimentos + 1 escritai visitas + 2 mudanças
Achar um valoraté n leiturasaté n visitas

Quando usar

Uma lista encadeada é uma boa escolha quando a maior parte das mudanças acontece num lugar para o qual você já tem um ponteiro, como a frente, e você raramente precisa da posição i. Filas e pilhas podem ser construídas com listas encadeadas, assim como as cadeias dentro de uma tabela hash, na próxima unidade. Há variantes. Uma lista duplamente encadeada dá a cada nó também um ponteiro prev, para que você possa andar para trás e apagar um nó em um passo depois de tê-lo nas mãos. Guardar um ponteiro tail além de head deixa barato acrescentar no fim.

No JavaScript do dia a dia, você raramente escreve uma lista encadeada, porque os arrays são bem otimizados e os caches dos processadores modernos favorecem valores guardados lado a lado. A ideia importa mesmo assim: árvores, grafos e muitas estruturas de bibliotecas são construídos com nós e ponteiros exatamente desse jeito.

ContextoAs listas encadeadas surgiram em meados da década de 1950 com a Information Processing Language (IPL), escrita por Allen Newell, Cliff Shaw e Herbert Simon na RAND Corporation e no Carnegie Institute of Technology por volta de 1956. Os programas deles buscavam provas de teoremas de lógica, e o número e o tamanho das coisas que precisavam lembrar não podiam ser conhecidos de antemão. Listas de células encadeadas permitiam distribuir e recolher memória uma célula de cada vez. O processamento de listas da IPL influenciou o Lisp, que John McCarthy projetou alguns anos depois.
  1. Quais dois campos um nó de lista simplesmente encadeada guarda?
    • item e next
    • índice e valor
    • esquerda e direita
    • head e tail
  2. Lista 12 → 7 → 30 → 4. Quantos passos leva inserir um valor novo na frente (mudanças de ponteiro)?
  3. Mesma lista: inserir na posição 2 custa quantos passos (visitas mais mudanças de ponteiro)?
  4. Mesma lista: quantos nós uma busca por 30 visita?
  5. Mesma lista: quantos nós uma busca por 99 visita antes de chegar a null?
  6. Mesma lista: apagar o nó na posição 3 (o 4) custa quantos passos?
  7. Um array tem 1000 valores e espaço de sobra. Quantos passos leva inserir na frente?
  8. Qual trabalho combina mais com uma lista encadeada do que com um array?
    • Ler muitas vezes o valor na posição 500
    • Acrescentar e remover na frente muitas vezes
    • Busca binária
    • Ordenar por índice
  9. Ao inserir depois do nó p, qual ordem de passos preserva o resto da lista?
    • p.next = new, depois new.next = p.next
    • new.next = p.next, depois p.next = new
    • Qualquer ordem funciona
    • Apagar p primeiro
  10. Qual linguagem, escrita por volta de 1956 na RAND, introduziu o processamento de listas com células encadeadas?
    • Fortran
    • IPL
    • C
    • JavaScript
Pontos-chave
  • Uma lista encadeada guarda cada valor num nó com um ponteiro next; a lista guarda head.
  • Inserir ou apagar na frente muda 1 ou 2 ponteiros; nada se move.
  • Chegar à posição i leva i + 1 visitas, então get at(i) é O(n).
  • Defina new.next antes de religar o nó anterior.
Fontes deste curso (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
  • 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
  • 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
  • MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
  • Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
  • ECMAScript 2025 Language Specification (tc39.es/ecma262)
  • 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
  • Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
  • D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
  • "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).

Data de verificação: 2026-10-18