
Table of Contents
What Is Dijkstra's Algorithm?
Dijkstra's algorithm, published by Edsger W. Dijkstra in 1959, finds the shortest path from a single source to every other node in a weighted graph. It works on both directed and undirected graphs, with one firm condition: every edge weight must be non-negative.
Think of the graph as a road network. Nodes are intersections, edges are roads, and each weight is the time or distance to travel that road. Dijkstra's algorithm answers the question every navigation app asks: what is the fastest route from where I am to everywhere else? It is one entry in the broader family covered in shortest path algorithms, and a fixture of the graph theory study roadmap.
The Core Idea
Dijkstra's algorithm is greedy. It keeps a tentative shortest distance to every node, and it repeats one simple move:
Always visit the unvisited node with the smallest known distance, then use it to improve its neighbours.
The insight that makes this correct: because all weights are non-negative, once you pick the closest unvisited node, no future path can ever reach it more cheaply. So the moment a node is chosen, its distance is final. That single guarantee is the whole algorithm.
Concretely, the algorithm maintains:
- A distance to every node, all starting at infinity except the source, which is
0. - A priority queue (min-heap) that always hands back the closest unvisited node.
- A set of finalized nodes whose shortest distance is settled.
Improving a neighbour is called relaxation: if the path through the current node is shorter than the neighbour's recorded distance, you lower it.
How It Works, Step by Step
Let's run Dijkstra from node A on this weighted graph. The blue edges will form the final shortest-path tree, and the number beside each node is its final shortest distance from A.
Here is the trace. At each step we finalize the closest unvisited node (bold) and relax its neighbours. ∞ means "not reached yet".
| Visit | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| Start | 0 | ∞ | ∞ | ∞ | ∞ | ∞ |
| A (0) | 0 | 4 | 2 | ∞ | ∞ | ∞ |
| C (2) | 0 | 3 | 2 | 10 | ∞ | ∞ |
| B (3) | 0 | 3 | 2 | 8 | ∞ | ∞ |
| D (8) | 0 | 3 | 2 | 8 | 10 | 14 |
| E (10) | 0 | 3 | 2 | 8 | 10 | 13 |
| F (13) | 0 | 3 | 2 | 8 | 10 | 13 |
Notice step three: visiting C lowered B from 4 to 3, because the route A → C → B (2 + 1) beats the direct edge A → B (4). That is relaxation doing its job. Watching this unfold on a live graph makes the pattern instant, which you can do in the algorithm visualizer.
Implementation in Python
The clean, interview-ready version uses Python's heapq as the priority queue. The graph is an adjacency list mapping each node to a list of (neighbour, weight) pairs.
import heapq
def dijkstra(graph, start):
# Every node starts infinitely far away, except the source.
distances = {node: float('inf') for node in graph}
distances[start] = 0
pq = [(0, start)] # (distance so far, node)
while pq:
dist, node = heapq.heappop(pq)
# A stale, longer entry for a node we already settled: skip it.
if dist > distances[node]:
continue
for neighbour, weight in graph[node]:
new_dist = dist + weight
# Relaxation: found a cheaper way to reach the neighbour.
if new_dist < distances[neighbour]:
distances[neighbour] = new_dist
heapq.heappush(pq, (new_dist, neighbour))
return distances
Two details matter. First, we push a new entry instead of updating the heap in place, then skip stale entries with the dist > distances[node] check. This "lazy deletion" keeps the code simple and is standard practice. Second, the algorithm naturally computes distances to all nodes; to stop early at a single target, return as soon as you pop it.
Time and Space Complexity
The cost depends on the priority queue. Each edge can trigger at most one push, and each push or pop on a binary heap costs O(log V).
| Priority queue | Time | Best when |
|---|---|---|
| Binary heap | O((V + E) log V) | The usual choice, sparse graphs |
| Fibonacci heap | O(E + V log V) | Dense graphs, theoretical best |
| Plain array | O(V²) | Very dense graphs |
Space is O(V) for the distance table plus the queue. For the reasoning behind these bounds and how they compare across every graph algorithm, see the graph algorithms complexity guide and the one-page cheat sheet.
When Dijkstra Fails: Negative Weights
The greedy guarantee rests entirely on non-negative weights. Add a negative edge and the whole thing can break.
Suppose the algorithm finalizes a node because it looks closest, distance 5. Later it discovers a longer-looking route that passes through a -4 edge and actually reaches that node in 3. Too late: Dijkstra already declared 5 final and moved on. The answer is wrong.
Rule to remember: non-negative weights, use Dijkstra. Any negative weight, use Bellman-Ford, which relaxes every edge repeatedly and can also detect negative cycles.
Dijkstra vs Other Algorithms
Dijkstra is one tool among several. Picking the right one comes down to the graph.
| Algorithm | Negative weights? | Best for | Time |
|---|---|---|---|
| BFS | Unweighted only | Unweighted shortest path | O(V + E) |
| Dijkstra | No | Non-negative weights | O((V + E) log V) |
| Bellman-Ford | Yes | Negative weights, cycle check | O(V · E) |
| A* | No | One target, with a heuristic | O(E) typical |
The closest relative is A* search, which is Dijkstra plus a heuristic that steers the search toward a single goal. And Dijkstra itself is really breadth-first search upgraded from a plain queue to a priority queue.
Real-World Applications
- Navigation and maps: the shortest or fastest route between two places, the classic use.
- Network routing: link-state protocols such as OSPF use Dijkstra to compute forwarding tables.
- Games and robotics: movement costs across a map, often with A* built on top.
- Operations and logistics: least-cost paths in supply, telecom, and transit networks, a staple of operations research.
Watch Dijkstra choose its next node
The priority queue clicks the instant you see it pull the cheapest node, over and over. Run Dijkstra on a live graph, step by step.
Open the Algorithm VisualizerFrequently Asked Questions
What does Dijkstra's algorithm do?
Dijkstra's algorithm finds the shortest path from a single source node to every other node in a weighted graph, as long as all edge weights are non-negative. It is the standard method behind routing, mapping, and network protocols.
What is the time complexity of Dijkstra's algorithm?
With a binary heap as the priority queue, Dijkstra's algorithm runs in O((V + E) log V) time and O(V) space. With a Fibonacci heap it improves to O(E + V log V), and with a plain array it is O(V squared), which is faster on dense graphs.
Why does Dijkstra's algorithm not work with negative weights?
Dijkstra finalizes each node as soon as it is removed from the priority queue, assuming no cheaper path can appear later. A negative edge breaks that assumption, because a longer route could still lower the total cost. Use Bellman-Ford for graphs with negative weights.
Is Dijkstra's algorithm the same as BFS?
Dijkstra generalizes breadth-first search. BFS uses a plain queue and finds the shortest path in unweighted graphs. Dijkstra replaces the queue with a min-priority queue, so it always expands the closest unvisited node and handles weighted edges.