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, 4Modificare 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.
Trascina per ruotare. Scorri o avvicina le dita per lo zoom.
| Operazione | Array (n valori) | Lista concatenata (n nodi) |
|---|---|---|
| Prendere il valore in posizione i | 1 | i + 1 visite |
| Inserire in testa | n spostamenti + 1 scrittura | 2 modifiche di puntatori |
| Eliminare la testa | 1 lettura + (n − 1) spostamenti | 1 modifica di puntatore |
| Inserire in posizione i | (n − i) spostamenti + 1 scrittura | i visite + 2 modifiche |
| Trovare un valore | fino a n letture | fino 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.
- Quali due campi contiene un nodo di una lista concatenata semplice?
- item e next
- indice e valore
- left e right
- head e tail
- Lista 12 → 7 → 30 → 4. Quanti passi richiede inserire un nuovo valore in testa (modifiche di puntatori)?
- Stessa lista: inserire in posizione 2 costa quanti passi (visite più modifiche di puntatori)?
- Stessa lista: quanti nodi visita una ricerca di 30?
- Stessa lista: quanti nodi visita una ricerca di 99 prima di arrivare a null?
- Stessa lista: eliminare il nodo in posizione 3 (il 4) costa quanti passi?
- Un array contiene 1000 valori e ha spazio libero. Quanti passi richiede inserire in testa?
- 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
- 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
- Quale linguaggio, scritto intorno al 1956 alla RAND, introdusse l'elaborazione di liste con celle collegate?
- Fortran
- IPL
- C
- JavaScript
- 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