edubun
Italiano

Liste concatenate

Aggiungere un valore in testa a una lista concatenata cambia due puntatori, che la lista contenga 4 valori o 4 milioni.

Valori che puntano al successivo

Un array tiene i valori uno accanto all'altro, ed è per questo che cambiarne la testa costa caro. Una lista concatenata abbandona questa regola. Ogni valore vive in un piccolo record tutto suo chiamato nodo, e i nodi possono stare in qualsiasi punto della memoria. Gli appunti del corso 6.006 del MIT descrivono un nodo con due campi: l'elemento e next, un puntatore al nodo seguente. La lista ricorda soltanto il primo nodo, chiamato head (testa). Il next dell'ultimo nodo è null, e segna la fine.

Per leggere la lista parti da head e segui i puntatori next uno alla volta, come una catena di bigliettini in cui ognuno dice dove è nascosto il successivo. Questo ha un costo. Non esiste una formula per l'indirizzo del quarto nodo, quindi prendere il valore in posizione i significa visitare i + 1 nodi. Il MIT indica get at(i) per una lista concatenata come O(n), mentre l'array lo faceva in un passo.

// un nodo per valore: { value, next }
let head = null;
for (const v of [4, 30, 7, 12]) head = { value: v, next: head };
// percorri la lista
for (let n = head; n !== null; n = n.next) console.log(n.value); // 12, 7, 30, 4

Modificare la lista ricollegando

Il vantaggio arriva quando modifichi la lista. Per mettere un nuovo valore in testa, crea un nodo il cui next è l'attuale head, poi fai puntare head al nuovo nodo. Due modifiche di puntatori, e nient'altro si sposta. Eliminare il nodo in testa è una sola modifica: fai puntare head a head.next. Confrontalo con l'array, dove le stesse operazioni spostavano ogni valore.

Nel mezzo, il lavoro sta nel trovare il punto giusto. Per inserire in posizione i cammini fino al nodo subito prima (i visite), poi fai le stesse due modifiche di puntatori: new.next = prev.next, poi prev.next = new. L'ordine conta. Se imposti prima prev.next, il resto della lista va perso, perché niente punta più a esso. Nel laboratorio un passo è un nodo visitato o un puntatore modificato, quindi inserire in posizione 2 in una lista di 4 nodi costa 2 visite più 2 modifiche, cioè 4 passi.

Caricamento

Trascina per ruotare. Scorri o avvicina le dita per lo zoom.

Una lista concatenata semplice di quattro nodi. Scegli una posizione con il cursore e inserisci o elimina; il contatore separa i nodi visitati dai puntatori modificati. Trova cammina da head finché incontra il valore o null.
OperazioneArray (n valori)Lista concatenata (n nodi)
Prendere il valore in posizione i1i + 1 visite
Inserire in testan spostamenti + 1 scrittura2 modifiche di puntatori
Eliminare la testa1 lettura + (n − 1) spostamenti1 modifica di puntatore
Inserire in posizione i(n − i) spostamenti + 1 scritturai visite + 2 modifiche
Trovare un valorefino a n letturefino a n visite

Quando usarla

Una lista concatenata è adatta quando la maggior parte delle modifiche avviene in un punto di cui hai già un puntatore, come la testa, e raramente ti serve la posizione i. Code e pile si possono costruire con liste concatenate, e così le catene dentro una tabella hash nella prossima unità. Esistono varianti. Una lista doppiamente concatenata dà a ogni nodo anche un puntatore prev, così puoi camminare all'indietro ed eliminare un nodo in un passo una volta che lo hai. Tenere un puntatore tail oltre a head rende economico aggiungere in fondo.

Nel JavaScript di tutti i giorni scrivi raramente una lista concatenata, perché gli array sono ben ottimizzati e le cache dei processori moderni favoriscono i valori memorizzati uno accanto all'altro. L'idea conta comunque: alberi, grafi e molte strutture delle librerie sono costruiti con nodi e puntatori proprio in questo modo.

ContestoLe liste concatenate comparvero a metà degli anni 1950 con l'Information Processing Language (IPL), scritto da Allen Newell, Cliff Shaw e Herbert Simon alla RAND Corporation e al Carnegie Institute of Technology intorno al 1956. I loro programmi cercavano dimostrazioni di teoremi di logica, e il numero e la grandezza delle cose da ricordare non si potevano conoscere in anticipo. Le liste di celle collegate permettevano di assegnare e restituire la memoria una cella alla volta. L'elaborazione di liste di IPL influenzò il Lisp, che John McCarthy progettò qualche anno dopo.
  1. Quali due campi contiene un nodo di una lista concatenata semplice?
    • item e next
    • indice e valore
    • left e right
    • head e tail
  2. Lista 12 → 7 → 30 → 4. Quanti passi richiede inserire un nuovo valore in testa (modifiche di puntatori)?
  3. Stessa lista: inserire in posizione 2 costa quanti passi (visite più modifiche di puntatori)?
  4. Stessa lista: quanti nodi visita una ricerca di 30?
  5. Stessa lista: quanti nodi visita una ricerca di 99 prima di arrivare a null?
  6. Stessa lista: eliminare il nodo in posizione 3 (il 4) costa quanti passi?
  7. Un array contiene 1000 valori e ha spazio libero. Quanti passi richiede inserire in testa?
  8. Quale lavoro si addice più a una lista concatenata che a un array?
    • Leggere molte volte il valore in posizione 500
    • Aggiungere e togliere molte volte in testa
    • Ricerca binaria
    • Ordinare per indice
  9. Inserendo dopo il nodo p, quale ordine dei passi conserva il resto della lista?
    • p.next = new, poi new.next = p.next
    • new.next = p.next, poi p.next = new
    • Va bene qualsiasi ordine
    • Prima elimina p
  10. Quale linguaggio, scritto intorno al 1956 alla RAND, introdusse l'elaborazione di liste con celle collegate?
    • Fortran
    • IPL
    • C
    • JavaScript
Punti chiave
  • Una lista concatenata memorizza ogni valore in un nodo con un puntatore next; la lista tiene head.
  • Inserire o eliminare in testa cambia 1 o 2 puntatori; niente si sposta.
  • Raggiungere la posizione i richiede i + 1 visite, quindi get at(i) è O(n).
  • Imposta new.next prima di ricollegare il nodo precedente.
Fonti di questo corso (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).

Consultato il: 2026-10-18