ABSTRACT
While BFS finds the shortest path in unweighted graphs (least number of edges), it fails when edges have varying costs. Dijkstra’s Algorithm is a Greedy Algorithm that solves the Single-Source Shortest Path problem for weighted graphs, provided all edge weights are non-negative.
- Category: Graph Traversal / Greedy Algorithm
- Input: Directed graph with edge weights , source vertex
- Output:
dist(v)— the shortest total weight from to every vertex- Paradigm: Greedy, priority-queue-driven frontier expansion
- Typical use cases: shortest path in weighted graphs (non-negative weights), routing, network cost minimization
Core Logic: Greedy Shortest Path
Why BFS Fails on Weighted Graphs
BFS assumes that every edge has a cost of . In a weighted graph, a path with more edges might actually have a lower total weight than a direct edge.
- BFS Path: (Total Weight: 30)
- Shortest Weighted Path: (Total Weight: )
Dijkstra’s Algorithm accounts for these costs by prioritizing paths with the smallest cumulative weight.
The Greedy Strategy
Dijkstra’s is a Greedy Algorithm. It makes the optimal choice at each step — picking the closest unvisited vertex — and assumes that this choice will lead to the overall shortest path.
Key Idea
- Assign a Distance of infinity to all nodes, except the start node (which is 0).
- Maintain a Priority Queue to store
(distance, vertex)pairs.- Always “relax” the neighbor: if the path to a neighbor through the current node is shorter than its previously known distance, update its distance and add it to the PQ.
- Once a node is “Done” (dequeued), its shortest path is guaranteed.
Pseudocode (Mid-Level Implementation)
High-Level Implementation
Dijkstra’s uses a Priority Queue to efficiently find the next vertex with the minimum distance.
Algorithm 29 Dijkstra's High Level
procedure Dijkstra's()
= empty, =
Initialize for all
while is not empty do
Pick in that has the
for each neighbor of do
if then
move to
move from to
Variables & Data Structures
| Name | Type | Purpose |
|---|---|---|
X | Set | Vertices whose shortest distance is finalized (“Done”) |
F | Set / Priority Queue | Frontier — vertices discovered but not yet finalized, keyed by dist |
dist | Array (vertex → number) | Best known distance from to each vertex; starts at except |
prev | Array (vertex → vertex) | Predecessor pointer, used to reconstruct the shortest path (low-level version) |
ℓ(v, u) | Edge weight function | The cost of traveling directly from to |
Helper Functions / Operations Used
- “Relax” an edge — if , update and re-prioritize it in the queue
deletemin(H)— pop the vertex with the smallest currentdistvaluedecreasekey(H, v)— lower the priority (distance key) ofvin the priority queue after a successful relaxation
Pick in carefully Dijkstra's Algorithm falls into a problem where vertices may re-enter more than once. If we pick in carefully (always the minimum
dist), we can avoid this — this is exactly what a priority queue gives us for free.
Optional Low-Level Implementation Full implementation using an explicit priority queue with
deletemin/decreasekey:Algorithm 30 Dijkstra
procedure Dijkstra()
for all do
dist()
prev() null
dist()
:= makequeue()
while is not empty do
deletemin()
for all edges do
if dist() > dist() + then
dist() dist() +
prev()
decreasekey()
Proof of Correctness
Claim: Let be the length of the shortest path from to . Then after every iteration, for all vertices in .
This claim implies that once a vertex moves into , it will never move back to . Therefore, every vertex enters at most once.
Base Case: The first vertex to move into is → .
Inductive Hypothesis: After vertices have been moved into , assume for all vertices in .
Inductive Step: Suppose is the next vertex to move into . Want to show .
Suppose by contradiction that , implying there exists a path such that . goes from to , so there is an edge that crosses the boundary of (with , ):

- by the inductive hypothesis
- by choice of (Dijkstra always picks the minimum-
distvertex in next)
Therefore:
\begin{align*} d(u) &= \underbrace{ len(P) }_{ s \to u } \geq \underbrace{ dist(w) + \ell(w,y) }_{ s \to y } \ &= dist(y) \geq dist(u) > d(u)\ &\therefore \boxed{d(u) > d(u)} \end{align*}
This is a contradiction, so the negation of our assumption must be true: .
Time & Space Complexity Analysis
General Case
Total runtime is:
Different implementations of Priority Queue have different trade-offs between the costs of
deleteminanddecreasekey. There isn't a single implementation that's optimal for all kinds of graphs.
Implementation-Dependent Variations
Array as a Priority Queue
Indexed by vertices, giving key value directly (e.g. Array[A] = 2, Array[B] = 9, …).
deletemin: — need to scan through the array to find which node contains the smallest distancedecreasekey: — array access by index means you can immediately find and update the (key, value) pair
Total Runtime:
Binary Heap as Priority Queue
Binary Heap A complete binary tree of objects (vertices) with the property that each key value of an object is less than or equal to the key value of its children.
- Can be implemented with an array of vertices
- The children of are and
- The parent of is
deletemin: The minimum key is guaranteed to be the root. Removing it requires replacing the root with the last object and letting it trickle down — where , so .decreasekey: Decreasing a key may require the object to bubble up — where , so .
How do we know where is in the binary heap? Keep a supplemental array (address book) indexed by , with pointers in both directions between this array and the binary heap elements.
Total Runtime:
Priority Queue Operations Overview
| What it does | Array Implementation | Heap Implementation | Number of Operations | |
|---|---|---|---|---|
insert | Add a new element with its priority value to the queue | — just append to end | — add to end, then bubble up | |
deletemin | Extract the unvisited vertex with the smallest distance | — must scan entire array to find minimum | — remove root, move last to the top, bubble down | |
decreasekey | If you find a shorter path to a vertex, update its distance in the queue | — access by index | — update value, bubble up |
When to Use Which Implementation
| Array | Binary Heap | |
|---|---|---|
| Sparse Graphs: | ✘ | ✔ |
| Dense Graphs: | ✔ | ✘ |
Best / Worst / Average Case
- Best / Worst / Average case: All the same order for a given PQ implementation — Dijkstra always processes every vertex once (
deletemin) and considers every edge once (decreasekey/relaxation attempt), so there’s no early-exit case that changes the asymptotic bound.
Drawbacks / Constraints
- Preconditions: Requires all edge weights to be non-negative.
- The Negative Weight Problem: Dijkstra’s Algorithm does not work with negative edge weights.
- The Reason: Dijkstra assumes that once a node is marked “Done,” no future path can possibly be shorter.
- The Failure: A negative edge could “reduce” the cost of a path discovered later, breaking the greedy assumption.
- Not suitable for: Graphs with negative edge weights — use Bellman-Ford Algorithm instead.
- Alternatives to consider: Breadth First Search (BFS) if all edges have equal weight (simpler, same runtime without needing a priority queue).
Comparison of Shortest Path Algorithms
| Algorithm | Graph Type | Guaranteed Shortest Path? |
|---|---|---|
| BFS | Unweighted | Yes (by edge count) |
| DFS | Any | No |
| Dijkstra | Weighted (Positive only) | Yes (by total weight) |