ALGORITMO: DIJKSTRA
L’algoritmo di Dijkstra calcola i percorsi minimi da un nodo sorgente a tutti gli altri nodi
in un grafo orientato o non orientato pesato, con pesi non negativi.
È uno degli algoritmi fondamentali per il calcolo di percorsi minimi in informatica e nelle reti.
PRECONDIZIONI
- Il grafo può essere orientato o non orientato.
- I pesi degli archi devono essere non negativi.
- Non gestisce correttamente grafi con archi a peso negativo (per quelli serve Bellman-Ford).
TERMINOLOGIA
- Vertice (Vertex) → nodo del grafo.
- Arco Pesato (Weighted Edge) → connessione tra due vertici con peso associato.
- Distanza → costo cumulativo minimo dal nodo sorgente a un nodo.
- Predecessore (Parent/Predecessor) → nodo precedente lungo il percorso minimo.
- Coda di Priorità (Priority Queue / Min-Heap) → struttura utilizzata per selezionare il nodo con distanza minima.
OPERAZIONI PRINCIPALI
aggiungiVertice(v)→ inserisce un nuovo vertice nel grafo.aggiungiArco(v1, v2, peso)→ aggiunge un arco orientato o non orientato con peso.dijkstra(start)→ calcola i percorsi minimi dal nodo sorgentestarta tutti gli altri nodi, restituendo:- le distanze minime
- i predecessori per ricostruire i percorsi.
RAPPRESENTAZIONE
- Lista di adiacenza con pesi:
Esempio →{ A: [{node: B, peso: 4}, {node: C, peso: 2}], B: [{node: C, peso: 5}], ... }
FUNZIONAMENTO DELL’ALGORITMO
- Inizializza tutte le distanze a ∞, eccetto il nodo sorgente (distanza = 0).
- Inserisci tutti i nodi in una coda di priorità basata sulla distanza minima.
- Finché la coda non è vuota:
- Estrai il nodo con distanza minima.
- Aggiorna le distanze dei suoi vicini se si trova un percorso più corto.
- Aggiorna i predecessori dei vicini per tracciare il percorso minimo.
- Al termine, si ottengono:
- la distanza minima da sorgente a ogni nodo
- il cammino più breve ricostruibile seguendo i predecessori.
COMPLESSITÀ
- Inserimento vertice → O(1)
- Inserimento arco → O(1)
- Calcolo percorso minimo:
- Con min-heap / coda di priorità → O(V + E log V)
- Con semplice array → O(V^2)
ESEMPIO DI USCITA
Grafo: A -> B(4), C(2) B -> C(5), D(10) C -> D(3), E(4) D -> E(7) E ->
Distanze minime da A: { A: 0, B: 4, C: 2, D: 5, E: 6 }
Predecessori: { A: null, B: ‘A’, C: ‘A’, D: ‘C’, E: ‘C’ }
Percorso minimo da A a E: A → C → E, costo 6.
APPLICAZIONI
- Reti stradali e navigazione GPS.
- Routing nei protocolli di rete (es. OSPF).
- Pianificazione dei percorsi in sistemi di trasporto.
- Problemi di logistica e distribuzione.
NOTE
- Adatto solo a pesi non negativi.
- Per grafi con pesi negativi → usare Bellman-Ford.
- La scelta della struttura dati per la coda di priorità influisce direttamente sulle prestazioni.
- Supporta sia grafi orientati che non orientati.
- Può essere esteso per trovare percorsi minimi verso un singolo nodo o verso tutti i nodi.
CODICE
import { DirectedGraph, Edge } from "../structure/orientedGraph";
/**
* Trova il nodo non visitato con distanza minima
*/
function minDistanza<E>(
distanze: Record<string, number>,
visitati: Set<string>
): string | null {
let min = Infinity;
let minNode: string | null = null;
for (const node in distanze) {
if (!visitati.has(node) && distanze[node] < min) {
min = distanze[node];
minNode = node;
}
}
return minNode;
}
/**
* Algoritmo di Dijkstra esterno
* @param graph Grafo orientato pesato
* @param start Nodo sorgente
* @returns Oggetto contenente distanze minime e predecessori
*/
export function dijkstra<E>(
graph: DirectedGraph<E>,
start: string
): { distanze: Record<string, number>; predecessori: Record<string, string | null> } {
const distanze: Record<string, number> = {};
const predecessori: Record<string, string | null> = {};
const visitati = new Set<string>();
const adjacencyList = graph.getAdjacencyList(); // Map<E, Edge<E>[]>
// Inizializzazione
for (const [vertice] of adjacencyList) {
const key = String(vertice);
distanze[key] = Infinity;
predecessori[key] = null;
}
distanze[start] = 0;
while (visitati.size < adjacencyList.size) {
const nodoCorrente = minDistanza(distanze, visitati);
if (!nodoCorrente) break;
visitati.add(nodoCorrente);
const edges = adjacencyList.get(nodoCorrente as unknown as E) ?? [];
for (const edge of edges) {
const targetKey = String(edge.nodo);
const nuovaDistanza = distanze[nodoCorrente] + edge.peso;
if (nuovaDistanza < distanze[targetKey]) {
distanze[targetKey] = nuovaDistanza;
predecessori[targetKey] = nodoCorrente;
}
}
}
return { distanze, predecessori };
}
// =============================
// Esempio di utilizzo
// =============================
const graph = new DirectedGraph<string>();
graph.aggiungiArco('A', 'B', 4);
graph.aggiungiArco('A', 'C', 2);
graph.aggiungiArco('B', 'C', 5);
graph.aggiungiArco('B', 'D', 10);
graph.aggiungiArco('C', 'D', 3);
graph.aggiungiArco('D', 'E', 7);
graph.aggiungiArco('C', 'E', 4);
graph.display();
const risultato = dijkstra<string>(graph, 'A');
console.log('Distanze minime da A:', risultato.distanze);
console.log('Predecessori:', risultato.predecessori);