Algoritmo de Dijkstra
Última actualización
El algoritmo de Dijkstra encuentra el camino más corto desde un nodo origen hasta todos los demás nodos de un grafo con pesos de arista no negativos. Mantiene una distancia tentativa para cada nodo, fija repetidamente el nodo no fijado con la menor distancia tentativa y relaja sus aristas, actualizando la distancia de un vecino cada vez que se encuentra una ruta más corta a través del nodo actual. Pulsa reproducir arriba para ver cómo bajan las distancias a medida que se fija cada nodo.
La idea clave es voraz: una vez que se elige el nodo no fijado más cercano, su distancia es definitiva, porque cualquier otra ruta hacia él tendría que pasar por un nodo que ya está más lejos. Con una cola de prioridad basada en montículo binario, Dijkstra se ejecuta en tiempo O((V + E) log V). Requiere pesos no negativos: usa Bellman-Ford si las aristas pueden ser negativas.
Complejidad temporal y espacial
| Implementación | Complejidad | Notas |
|---|---|---|
| Montículo binario | O((V + E) log V) | La opción común y práctica |
| Barrido de array | O(V²) | Más simple; adecuado para grafos densos |
| Espacio | O(V) | Distancias + cola de prioridad |
| Requiere | Pesos no negativos | Las aristas negativas rompen la elección voraz |
Paso a paso
| Paso | Qué ocurre |
|---|---|
| 1 | Fija la distancia del origen en 0 y todas las demás en infinito. |
| 2 | Elige el nodo no fijado con la menor distancia tentativa. |
| 3 | Márcalo como fijado: su distancia más corta ya es definitiva. |
| 4 | Para cada vecino, calcula distancia-a-través-del-actual + peso de la arista. |
| 5 | Si es menor que la distancia actual del vecino, relájala. |
| 6 | Repite hasta fijar todos los nodos alcanzables. |
Ejemplo resuelto
Caminos más cortos desde el origen A en el grafo con aristas A-B=4, A-C=1, C-B=2, C-D=5, B-D=1:
| Paso | Fijar | Distancias | Acción |
|---|---|---|---|
| 0 | - | A=0, B=∞, C=∞, D=∞ | Inicializa: origen A=0, todos los demás infinito. |
| 1 | A (0) | B=4, C=1, D=∞ | Relaja las aristas desde A: fija B=4, C=1. |
| 2 | C (1) | B=3, D=6 | A través de C: B=1+2=3 mejora 4; D=1+5=6. |
| 3 | B (3) | D=4 | A través de B: D=3+1=4 mejora 6. |
| 4 | D (4) | A=0, C=1, B=3, D=4 | Fija D; no queda nada por relajar. Listo. |
Cuándo usar el algoritmo de Dijkstra
| Úsalo cuando | Evítalo cuando |
|---|---|
| Todos los pesos de arista son no negativos | Cualquier arista puede ser negativa: usa Bellman-Ford |
| Necesitas los caminos más cortos desde un origen a todos los nodos | Necesitas caminos más cortos entre todos los pares: Floyd-Warshall es más simple |
| El grafo es ponderado y quieres distancias exactas | El grafo no es ponderado: un BFS simple es más rápido y sencillo |
| Dispones de un buen montículo o cola de prioridad | Quieres llegar rápido a un único destino con una heurística: usa A* |
Código de Dijkstra's Algorithm
Una implementación limpia y ejecutable de Dijkstra's Algorithm en Python, JavaScript, Java, C++, C. Elige un lenguaje, copia el código o ábrelo ya cargado en el Playground de Coddy.
Código de Dijkstra's Algorithm en Python
1import heapq2
3
4def dijkstra(graph, start):5 dist = {node: float("inf") for node in graph}6 dist[start] = 07 pq = [(0, start)]8 while pq:9 d, node = heapq.heappop(pq)10 if d > dist[node]:11 continue # stale entry, a shorter path was already found12 for neighbor, weight in graph[node]:13 new_dist = d + weight14 if new_dist < dist[neighbor]:15 dist[neighbor] = new_dist16 heapq.heappush(pq, (new_dist, neighbor))17 return dist18
19
20graph = {21 "A": [("B", 4), ("C", 1)],22 "B": [("D", 1)],23 "C": [("B", 2), ("D", 5)],24 "D": [("E", 3)],25 "E": [],26}27
28for node, d in dijkstra(graph, "A").items():29 print(f"A -> {node}: {d}")Código de Dijkstra's Algorithm en JavaScript
1const graph = {2 A: { B: 4, C: 2 },3 B: { C: 5, D: 10 },4 C: { E: 3 },5 D: { F: 11 },6 E: { D: 4 },7 F: {},8};9
10function dijkstra(source) {11 const dist = {};12 const visited = new Set();13 for (const node in graph) dist[node] = Infinity;14 dist[source] = 0;15 while (visited.size < Object.keys(graph).length) {16 // JS has no built-in heap: linear scan for the closest node (O(V^2))17 let u = null;18 for (const node in dist) {19 if (!visited.has(node) && (u === null || dist[node] < dist[u])) {20 u = node;21 }22 }23 if (dist[u] === Infinity) break;24 visited.add(u);25 for (const [v, w] of Object.entries(graph[u])) {26 if (dist[u] + w < dist[v]) dist[v] = dist[u] + w;27 }28 }29 return dist;30}31
32console.log("Shortest distances from A:", dijkstra("A"));Código de Dijkstra's Algorithm en Java
1import java.util.ArrayList;2import java.util.Arrays;3import java.util.List;4import java.util.PriorityQueue;5
6public class Main {7 public static void main(String[] args) {8 int n = 6;9 List<List<int[]>> adj = new ArrayList<>();10 for (int i = 0; i < n; i++) adj.add(new ArrayList<>());11 int[][] edges = {12 {0, 1, 4}, {0, 2, 1}, {2, 1, 2}, {1, 3, 5},13 {2, 3, 8}, {3, 4, 3}, {2, 5, 10}, {4, 5, 2}14 };15 for (int[] e : edges) {16 adj.get(e[0]).add(new int[]{e[1], e[2]});17 adj.get(e[1]).add(new int[]{e[0], e[2]});18 }19
20 int[] dist = new int[n];21 Arrays.fill(dist, Integer.MAX_VALUE);22 dist[0] = 0;23 PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);24 pq.add(new int[]{0, 0}); // {node, distance}25 while (!pq.isEmpty()) {26 int[] cur = pq.poll();27 int node = cur[0], d = cur[1];28 if (d > dist[node]) continue; // stale queue entry29 for (int[] edge : adj.get(node)) {30 int next = edge[0], nd = d + edge[1];31 if (nd < dist[next]) {32 dist[next] = nd;33 pq.add(new int[]{next, nd});34 }35 }36 }37 System.out.println("Shortest distances from 0: " + Arrays.toString(dist));38 }39}Código de Dijkstra's Algorithm en C++
1#include <iostream>2#include <queue>3#include <vector>4
5int main() {6 const int INF = 1000000000;7 // Weighted directed graph: adj[u] = {(neighbor, weight), ...}8 std::vector<std::vector<std::pair<int, int>>> adj = {9 {{1, 4}, {2, 1}}, // 010 {{3, 1}}, // 111 {{1, 2}, {3, 5}}, // 212 {{4, 3}}, // 313 {}, // 414 };15 int n = static_cast<int>(adj.size());16 std::vector<int> dist(n, INF);17 dist[0] = 0;18 using State = std::pair<int, int>; // (distance, node)19 std::priority_queue<State, std::vector<State>, std::greater<State>> pq;20 pq.push({0, 0});21 while (!pq.empty()) {22 auto [d, u] = pq.top();23 pq.pop();24 if (d > dist[u]) continue; // stale queue entry25 for (auto [v, w] : adj[u]) {26 if (d + w < dist[v]) {27 dist[v] = d + w;28 pq.push({dist[v], v});29 }30 }31 }32 for (int v = 0; v < n; ++v) {33 std::cout << "Distance 0 -> " << v << ": " << dist[v] << "\n";34 }35 return 0;36}Código de Dijkstra's Algorithm en C
1#include <stdbool.h>2#include <stdio.h>3
4#define N 55#define INF 10000000006
7int main(void) {8 // Weighted directed graph: w[u][v] = 0 means no edge9 int w[N][N] = {10 {0, 4, 1, 0, 0},11 {0, 0, 0, 1, 0},12 {0, 2, 0, 5, 0},13 {0, 0, 0, 0, 3},14 {0, 0, 0, 0, 0},15 };16 int dist[N];17 bool done[N] = {false};18 for (int v = 0; v < N; v++) dist[v] = INF;19 dist[0] = 0;20 // O(V^2) scan for the closest unfinished node (no heap needed here)21 for (int iter = 0; iter < N; iter++) {22 int u = -1;23 for (int v = 0; v < N; v++) {24 if (!done[v] && (u == -1 || dist[v] < dist[u])) u = v;25 }26 if (dist[u] == INF) break; // remaining nodes are unreachable27 done[u] = true;28 for (int v = 0; v < N; v++) {29 if (w[u][v] > 0 && dist[u] + w[u][v] < dist[v]) {30 dist[v] = dist[u] + w[u][v];31 }32 }33 }34 for (int v = 0; v < N; v++) {35 printf("Distance 0 -> %d: %d\n", v, dist[v]);36 }37 return 0;38}Preguntas frecuentes sobre el algoritmo de Dijkstra
¿Cuál es la complejidad temporal del algoritmo de Dijkstra?
O((V + E) log V). Una versión simple que barre un array buscando el mínimo en cada paso es O(V²), que en realidad puede ser más rápida en grafos densos. Ambas usan espacio O(V).¿Por qué Dijkstra no funciona con pesos de arista negativos?
¿Cuál es la diferencia entre Dijkstra y BFS?
¿Cuál es la diferencia entre Dijkstra y la búsqueda A*?
¿Cuándo debería usar Dijkstra en lugar de Bellman-Ford?
O((V + E) log V) frente a O(V·E) de Bellman-Ford. Elige Bellman-Ford solo cuando las aristas pueden ser negativas o necesitas detectar ciclos negativos. En grafos no negativos Dijkstra casi siempre es la mejor opción.