Menu
Coddy logo textTech

Linked list (lista concatenata)

Ultimo aggiornamento

Una lista concatenata memorizza una sequenza come una catena di nodi, in cui ogni nodo contiene un valore e un puntatore al nodo successivo. A differenza di un array, i nodi non sono contigui in memoria: per scorrere la lista segui i puntatori next. Premi play qui sopra per vedere i nodi collegati in testa e in coda, la ricerca di un valore percorrendo la catena e la rimozione di un nodo ricollegando un puntatore.

Inserire o eliminare in testa è O(1) perché basta spostare il puntatore alla testa. Raggiungere una posizione in mezzo o la coda è O(n) perché prima devi arrivarci. Questo compromesso, estremità economiche e nessun accesso casuale, è ciò che distingue una lista concatenata da un array.

Complessità temporale

OperazioneComplessitàNote
Inserimento in testaO(1)Sposta head
Inserimento in codaO(n)Prima arriva alla fine (O(1) con un puntatore tail)
RicercaO(n)Segui i puntatori next
Eliminazione della testaO(1)Sposta head oltre il nodo
Accesso per indiceO(n)Nessun accesso casuale

Lista concatenata e array a confronto

AspettoLista concatenataArray
MemoriaNodi sparsi + puntatoriBlocco contiguo
Accesso casualeO(n)O(1)
Inserimento/eliminazione in testaO(1)O(n) (spostamento)
Uso della cacheScarsoBuono

Esempio svolto

Costruzione della lista [10, 20], inserimento di 5 in testa, poi eliminazione di 20:

PassoStrutturaAzione
Iniziohead -> nullLista vuota
Inserisci in testa 10head -> 10 -> nullSposta head su un nuovo nodo il cui next è la vecchia testa (null)
Inserisci in coda 20head -> 10 -> 20 -> nullArriva al nodo 10, imposta il suo next su un nuovo nodo 20
Inserisci in testa 5head -> 5 -> 10 -> 20 -> nullIl nuovo nodo 5 punta alla vecchia testa 10; ora head punta a 5
Elimina 20head -> 5 -> 10 -> nullArriva a 10, cambia il suo next da 20 a null; il nodo 20 viene scollegato

Quando usare una lista concatenata

Usala quandoEvitala quando
Inserisci o elimini alle estremità (o in un nodo di cui hai il riferimento) molto più spesso di quanto accedi per indiceTi serve un accesso casuale veloce per posizione (indicizzazione O(1))
La dimensione cambia molto e non vuoi costi di ridimensionamento o copiaEsegui cicli stretti in cui la località della cache domina le prestazioni
Stai costruendo una coda, una pila o una lista di adiacenzaLa memoria è poca: ogni nodo paga un puntatore in più per elemento
Ti servono riferimenti stabili ai nodi che sopravvivano agli inserimenti altroveLeggi soprattutto e modifichi di rado, quindi un array è più semplice e veloce

Codice Linked List

Un'implementazione di Linked List pulita ed eseguibile in Python, JavaScript, Java, C++, C. Scegli un linguaggio, copia il codice o aprilo già caricato nel Playground di Coddy.

Codice Linked List in Python

Python
1class Node:2    def __init__(self, value):3        self.value = value4        self.next = None5
6
7class LinkedList:8    def __init__(self):9        self.head = None10
11    def append(self, value):12        node = Node(value)13        if self.head is None:14            self.head = node15            return16        current = self.head17        while current.next:18            current = current.next19        current.next = node20
21    def find(self, value):22        current = self.head23        while current:24            if current.value == value:25                return True26            current = current.next27        return False28
29    def delete(self, value):30        # Re-link the previous node around the match31        current, prev = self.head, None32        while current:33            if current.value == value:34                if prev is None:35                    self.head = current.next36                else:37                    prev.next = current.next38                return True39            prev, current = current, current.next40        return False41
42    def __str__(self):43        values, current = [], self.head44        while current:45            values.append(str(current.value))46            current = current.next47        return " -> ".join(values) + " -> None"48
49
50lst = LinkedList()51for value in [3, 7, 1, 9]:52    lst.append(value)53
54print("List:    ", lst)55print("find(7): ", lst.find(7))56lst.delete(1)57print("After delete(1):", lst)
Esegui questo codice nel playground Python

Domande frequenti sulla lista concatenata

Qual è la differenza tra una lista concatenata e un array?
Un array memorizza gli elementi in un unico blocco contiguo, dando accesso casuale O(1) ma inserimenti ed eliminazioni O(n) che spostano gli elementi. Una lista concatenata memorizza i nodi ovunque in memoria collegandoli con puntatori, dando inserimenti ed eliminazioni O(1) in una posizione nota ma accesso O(n), perché devi percorrere la catena.
Quando conviene usare una lista concatenata?
Le liste concatenate danno il meglio quando inserisci o rimuovi spesso alle estremità (o in un nodo di cui hai già un riferimento) e raramente ti serve l'accesso casuale: per esempio code, pile, liste di adiacenza e cache LRU. Se ti serve un accesso veloce per indice, di solito è meglio un array o un array dinamico.
Qual è la complessità temporale di una lista concatenata?
Inserire o eliminare in testa è O(1). Cercare, o raggiungere la coda senza un puntatore tail, è O(n) perché segui i puntatori next uno per uno. Non c'è accesso casuale O(1): accedere per indice a una lista concatenata è O(n).
Qual è la differenza tra una lista semplicemente e una doppiamente concatenata?
Una lista semplicemente concatenata memorizza solo un puntatore next per nodo, quindi puoi scorrerla in una sola direzione ed eliminare un nodo richiede un riferimento al suo predecessore. Una lista doppiamente concatenata aggiunge un puntatore prev, che permette di scorrere all'indietro e di eliminare in O(1) un nodo di cui hai il riferimento, al costo di un puntatore in più per nodo e di più lavoro a ogni inserimento ed eliminazione.
Perché inserire in coda è O(n) se inserire in testa è O(1)?
Inserire in testa ricollega solo il puntatore head, un lavoro costante. Raggiungere la coda significa seguire i puntatori next dalla testa fino alla fine, cosa che è O(n). Tenere un puntatore tail separato rende anche l'inserimento in coda O(1), ed è per questo che le liste reali spesso tengono traccia di entrambe le estremità.
Le liste concatenate hanno inserimento O(1) ovunque?
No, è un equivoco comune. L'inserimento in sé è O(1) solo se hai già un puntatore al nodo dopo cui inserire. Trovare quella posizione per valore o per indice costa comunque O(n), perché devi percorrere la catena per arrivarci.
Illustrazione dei linguaggi di programmazione di Coddy

Padroneggia gli algoritmi con Coddy

INIZIA