Menu
Coddy logo textTech

Algoritmo di Prim

Ultimo aggiornamento

L'algoritmo di Prim costruisce un albero ricoprente minimo (MST), cioè l'insieme di archi più economico che collega tutti i nodi senza cicli, facendo crescere un unico albero verso l'esterno a partire da un nodo iniziale. A ogni passo esamina tutti gli archi che vanno dall'albero a un nodo esterno e aggiunge il più economico. Premi play qui sopra per vedere l'albero espandersi, prendendo sempre l'arco di peso minore che raggiunge un nuovo nodo.

Dato che sceglie sempre l'arco di attraversamento minimo, ogni aggiunta è sicura (garantita come parte di qualche MST). Con una coda di priorità basata su heap binario, indicizzata sull'arco più economico verso ogni nodo esterno, Prim richiede O(E log V). Si differenzia da Kruskal, che ordina globalmente tutti gli archi invece di far crescere un unico albero connesso.

Complessità temporale e spaziale

ImplementazioneComplessitàNote
Heap binarioO(E log V)Coda di priorità degli archi di attraversamento
Matrice di adiacenzaO(V²)Più semplice; buona per i grafi densi
SpazioO(V + E)Appartenenza all'albero + coda di priorità
Ideale perGrafi densiCresce da un unico nodo di partenza

Passo dopo passo

PassoCosa succede
1Inizia l'albero con un nodo qualsiasi.
2Esamina tutti gli archi che vanno dall'albero a un nodo esterno.
3Scegli l'arco di attraversamento con il peso più piccolo.
4Aggiungi all'albero quell'arco e il suo nuovo nodo.
5Ripeti finché tutti i nodi non sono nell'albero.

Esempio svolto

Costruzione dell'MST di un grafo con 4 nodi e gli archi A-B=1, A-C=3, B-C=2, B-D=4, C-D=5, partendo da A:

PassoAlberoArchi di attraversamentoArco scelto
1{A}A-B=1, A-C=3A-B (peso 1)
2{A, B}A-C=3, B-C=2, B-D=4B-C (peso 2)
3{A, B, C}B-D=4, C-D=5B-D (peso 4)
4{A, B, C, D}nessuno: tutti i nodi sono nell'alberofatto: peso dell'MST 1+2+4 = 7

Quando usare l'algoritmo di Prim

Usalo quandoEvitalo quando
Ti serve un albero ricoprente minimo di un grafo pesato, connesso e non orientato.Il grafo è orientato o ti servono i cammini minimi: usa invece Dijkstra o Bellman-Ford.
Il grafo è denso (E vicino a V²); la forma a matrice O(V²) è semplice e veloce.Il grafo è sparso e gli archi sono già ordinati o facili da ordinare: Kruskal spesso è più semplice.
Vuoi che l'albero cresca da una zona verso l'esterno (ad es. layout incrementale di una rete).Il grafo non è connesso: Prim copre una sola componente, e ti serve una foresta ricoprente minima.
Hai già a disposizione una struttura di adiacenza e una coda di priorità.Devi rilevare cicli su un insieme globale di archi: l'union-find (Kruskal) è più adatto a questo schema.

Codice Prim's Algorithm

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

Codice Prim's Algorithm in Python

Python
1import heapq2
3
4def prim(graph, start):5    visited = {start}6    heap = [(w, start, v) for v, w in graph[start]]7    heapq.heapify(heap)8    mst, total = [], 09    while heap and len(visited) < len(graph):10        w, u, v = heapq.heappop(heap)11        if v in visited:12            continue13        visited.add(v)14        mst.append((u, v, w))15        total += w16        # Offer the new node's edges to the frontier17        for neighbor, weight in graph[v]:18            if neighbor not in visited:19                heapq.heappush(heap, (weight, v, neighbor))20    return mst, total21
22
23graph = {24    "A": [("B", 4), ("C", 1)],25    "B": [("A", 4), ("C", 3), ("D", 2)],26    "C": [("A", 1), ("B", 3), ("D", 5)],27    "D": [("B", 2), ("C", 5), ("E", 7)],28    "E": [("D", 7)],29}30
31mst, total = prim(graph, "A")32for u, v, w in mst:33    print(f"{u} - {v} (weight {w})")34print("Total MST weight:", total)
Esegui questo codice nel playground Python

Domande frequenti sull'algoritmo di Prim

Qual è la complessità temporale dell'algoritmo di Prim?
Con una coda di priorità basata su heap binario, Prim richiede O(E log V). Una versione più semplice con matrice di adiacenza, che a ogni passo cerca l'arco di attraversamento minimo, è O(V²) e può essere più veloce sui grafi densi. Entrambe usano spazio O(V + E).
Qual è la differenza tra l'algoritmo di Prim e quello di Kruskal?
Entrambi trovano un albero ricoprente minimo in modo greedy. Prim fa crescere un unico albero connesso da un nodo di partenza, aggiungendo ripetutamente l'arco più economico che esce dall'albero (con una coda di priorità). Kruskal considera tutti gli archi ordinati per peso e aggiunge il più economico che non forma un ciclo (con l'union-find). Prim è spesso preferito sui grafi densi, Kruskal su quelli sparsi.
L'algoritmo di Prim trova sempre l'MST ottimale?
Sì. A ogni passo l'arco più economico che attraversa l'albero corrente è sicuro da aggiungere: appartiene a qualche albero ricoprente minimo (la proprietà del taglio). Aggiungere ripetutamente archi sicuri produce un vero albero ricoprente minimo, a patto che il grafo sia connesso.
Quando conviene usare l'algoritmo di Prim invece di quello di Kruskal?
Scegli Prim quando il grafo è denso, perché la sua forma O(V²) con matrice di adiacenza evita di ordinare tutti gli E archi e fa crescere un solo albero da un nodo di partenza. Kruskal dà il meglio sui grafi sparsi, dove ordinare la lista degli archi costa poco e l'union-find mantiene veloci i controlli sui cicli. Entrambi producono un MST corretto, quindi la scelta dipende soprattutto dalla densità degli archi e dalle strutture dati che hai già.
Il nodo di partenza influisce sull'MST risultante?
No: il peso totale dell'MST è lo stesso qualunque sia il nodo di partenza, perché il peso dell'albero ricoprente minimo di un grafo connesso è unico. Gli archi specifici possono cambiare solo quando più archi hanno lo stesso peso ed esistono più MST. Altrimenti Prim arriva esattamente allo stesso albero indipendentemente dal nodo iniziale.
L'algoritmo di Prim gestisce i grafi non connessi?
Non direttamente. Prim fa crescere un solo albero, quindi copre solo la componente connessa che contiene il nodo di partenza e lascia il resto intatto. Per coprire ogni componente dovresti eseguire Prim più volte da un nodo non visitato, producendo una foresta ricoprente minima invece di un unico albero.
Illustrazione dei linguaggi di programmazione di Coddy

Padroneggia gli algoritmi con Coddy

INIZIA