Skip to main content

Dijkstra's Algorithm

Aditya948351
EditReport

Dijkstra's Algorithm finds the shortest path from a single source vertex to all other vertices in a weighted graph.

Important Limitation

Dijkstra's algorithm is greedy and assumes all edge weights are non-negative. If a graph has negative edge weights, Dijkstra's algorithm might fail. Use the Bellman-Ford Algorithm instead in such cases.


Interactive Visualizationโ€‹

Below is an interactive visualizer for Dijkstra's algorithm. You can click Start Dijkstra to watch the algorithm explore nodes and update distances using a min-priority queue, or click Next Step to step through the execution manually!

0
1
2
3
4
5
6
7
8
9

How It Worksโ€‹

The algorithm uses a Min-Priority Queue to continually select the unvisited vertex with the smallest known distance from the source.

Stepsโ€‹

  1. Initialize the distance to the source node as 0, and all other nodes to โˆž.
  2. Insert all nodes into a priority queue based on their current distances.
  3. While the priority queue is not empty:
    • Extract the node u with the minimum distance.
    • For each neighbor v of u:
      • Calculate the new distance dist[u] + weight(u, v).
      • If this new distance is less than the current dist[v], update dist[v] and update the priority queue.

Complexity Analysisโ€‹

MetricValue
Time ComplexityO((V + E) log V)
Space ComplexityO(V)

Where V = number of vertices, E = number of edges. The time complexity assumes the use of a Priority Queue / Min-Heap.


Implementationsโ€‹

Pythonโ€‹

import heapq

def dijkstra(graph, start):
# Initialize distances
distances = {node: float('inf') for node in graph}
distances[start] = 0

# Priority queue stores (distance, node)
pq = [(0, start)]

while pq:
current_distance, current_node = heapq.heappop(pq)

# Optimization: ignore obsolete entries in the priority queue
if current_distance > distances[current_node]:
continue

for neighbor, weight in graph[current_node].items():
distance = current_distance + weight

if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))

return distances

Javaโ€‹

import java.util.*;

public class Dijkstra {
static class Node implements Comparable<Node> {
int vertex, weight;
Node(int v, int w) { vertex = v; weight = w; }
public int compareTo(Node other) { return Integer.compare(this.weight, other.weight); }
}

public static int[] dijkstra(int V, List<List<Node>> graph, int source) {
int[] dist = new int[V];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[source] = 0;

PriorityQueue<Node> pq = new PriorityQueue<>();
pq.add(new Node(source, 0));

while (!pq.isEmpty()) {
Node current = pq.poll();
int u = current.vertex;

if (current.weight > dist[u]) continue;

for (Node neighbor : graph.get(u)) {
int v = neighbor.vertex;
int weight = neighbor.weight;

if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.add(new Node(v, dist[v]));
}
}
}
return dist;
}
}

C++โ€‹

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

typedef pair<int, int> pii;

vector<int> dijkstra(int V, vector<vector<pii>>& graph, int source) {
vector<int> dist(V, 1e9); // 1e9 represents infinity
dist[source] = 0;

priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({0, source});

while (!pq.empty()) {
int d = pq.top().first;
int u = pq.top().second;
pq.pop();

if (d > dist[u]) continue;

for (auto edge : graph[u]) {
int v = edge.first;
int weight = edge.second;

if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
return dist;
}

JavaScriptโ€‹

class PriorityQueue {
constructor() { this.values = []; }
enqueue(val, priority) {
this.values.push({val, priority});
}
dequeue() {
let minIdx = 0;
for (let i = 1; i < this.values.length; i++) {
if (this.values[i].priority < this.values[minIdx].priority) {
minIdx = i;
}
}
return this.values.splice(minIdx, 1)[0];
}
isEmpty() { return this.values.length === 0; }
}

function dijkstra(graph, start) {
const distances = {};
const pq = new PriorityQueue();

for (let node in graph) {
distances[node] = Infinity;
}
distances[start] = 0;
pq.enqueue(start, 0);

while (!pq.isEmpty()) {
const {val: current_node, priority: current_distance} = pq.dequeue();

if (current_distance > distances[current_node]) continue;

for (let neighbor in graph[current_node]) {
let distance = current_distance + graph[current_node][neighbor];

if (distance < distances[neighbor]) {
distances[neighbor] = distance;
pq.enqueue(neighbor, distance);
}
}
}
return distances;
}

Real-World Use Casesโ€‹

  • Google Maps โ€” Routing and finding the fastest path between cities or locations.
  • Network Routing Protocols โ€” OSPF (Open Shortest Path First) uses Dijkstra's algorithm to compute the shortest path for data packets.
  • Video Games โ€” Pathfinding algorithms for NPCs to navigate maps while avoiding obstacles.
Finished reading? Mark this topic as complete.