What this module covers: Module A-5's BFS finds shortest paths measured in hop count — correct only when every edge costs the same. This module covers the weighted version: Dijkstra's algorithm, which is BFS with one structural swap — Module A-1's min-heap standing in for Module F-7's plain queue — always processing whichever unvisited node currently has the smallest known total distance, not just whichever was enqueued first.
Why BFS Breaks on Weighted Graphs
BFS's shortest-path guarantee (Module A-5) depends entirely on every edge costing exactly the same "1 hop." On a weighted graph, a path with fewer edges can easily cost more than a path with more edges that are individually cheaper — Module P-6 already flagged this exact failure mode. Dijkstra's algorithm fixes it by tracking actual accumulated cost, not hop count, and by always expanding outward from whichever reachable node currently has the smallest known cost — not whichever was simply discovered first.
The Algorithm: BFS With a Min-Heap Instead of a Queue
typescript
Compare this line-by-line against Module A-5's shortestPathLength: same overall shape (extract a node, look at its neighbors, push newly-discovered or improved distances), but Module F-7's plain FIFO queue is replaced by Module A-1's min-heap, and instead of tracking "distance = hop count," distances tracks actual accumulated edge weight. Always extracting the minimum is what makes this correct: once a node is popped from the min-heap, no undiscovered path could possibly reach it more cheaply, because every alternative path would have to go through some other node whose distance is at least as large as what's currently at the top of the heap — there's nothing left in the heap with a smaller distance that could somehow produce a shorter route.
Why This Only Works With Non-Negative Weights
The correctness argument above — "no path through a not-yet-processed node could possibly be cheaper" — depends entirely on edge weights never being negative. If a negative edge existed, a longer-looking path that later dips through a large negative weight could end up cheaper than a path Dijkstra already finalized and moved past, and Dijkstra has no mechanism to revisit a node it's already marked visited and committed to.
typescript
This is the same "greedy choice, provably correct only under specific conditions" theme from Module P-15 — Dijkstra's greedy "always expand the cheapest known frontier node" strategy has the greedy-choice property specifically because weights are non-negative, guaranteeing costs only ever grow as you extend a path further. Remove that guarantee, and the strategy silently produces wrong answers rather than failing loudly. Module A-7's Bellman-Ford algorithm exists specifically to handle graphs where negative weights are possible, using a different (and more expensive) strategy that doesn't rely on this assumption.
Where This Shows Up in Your Stack
GPS navigation and mapping services: finding the shortest (or fastest) route between two points on a road network, where each road segment has a real-world cost (distance, or estimated travel time) — a direct, large-scale application of exactly this algorithm, typically layered with further heuristics (A* search, using estimated remaining distance to prioritize promising directions) for speed at map scale.
Network routing protocols: OSPF (Open Shortest Path First) — right there in the name — computes shortest paths between routers using Dijkstra's algorithm directly, with edge weights representing link cost (bandwidth, latency, or administrative preference).
Any weighted graph problem framed as "cheapest way to get from A to B" where costs are guaranteed non-negative — cheapest sequence of currency conversions, minimum-cost dependency resolution when steps have varying cost, or latency-optimized service call chains in a microservice architecture — is a candidate for Dijkstra specifically because it's faster (O((V + E) log V) with a binary heap) than the more general algorithms Module A-7 covers, provided the non-negative-weight requirement genuinely holds.
Summary
Dijkstra's algorithm is BFS with Module A-1's min-heap replacing Module F-7's plain queue, and with distance tracked as accumulated edge weight rather than hop count.
Always extracting the minimum-distance node from the heap is what guarantees correctness: once popped, no remaining path through an unprocessed node could possibly be cheaper.
This guarantee depends entirely on non-negative edge weights — a negative edge could make a path Dijkstra already finalized and moved past turn out to be more expensive than an alternative it never reconsidered.
This is the same "greedy is only correct under specific conditions" lesson from Module P-15, applied to graph shortest paths rather than interval scheduling or knapsack.
This is the literal algorithm behind GPS routing and OSPF network routing — not just a conceptually similar idea, but the same computation, at real-world scale.
The next module, Shortest Paths II: Bellman-Ford and Floyd-Warshall, covers what happens when that non-negative-weight guarantee doesn't hold — and how to compute shortest paths between every pair of nodes at once, rather than from a single source.
Knowledge Check
Why does replacing Module F-7's plain queue with Module A-1's min-heap turn BFS's hop-count shortest path into Dijkstra's weighted shortest path?
Why does a negative edge weight break Dijkstra's correctness guarantee, using the module's example (A→B weight 5, A→C weight 2, C→B weight −10)?
According to the module, why is Dijkstra's "always expand the cheapest known frontier node" strategy described as a greedy algorithm with the same character as the ones covered in Module P-15?
Test your knowledge with more question sets
Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.
functiondijkstra( graph: Map<string,[string,number][]>,// node -> [neighbor, edge weight][] start:string): Map<string,number>{const distances =newMap<string,number>();const visited =newSet<string>();const minHeap =newMinHeap<[number,string]>(/* compare by first element — distance */); distances.set(start,0); minHeap.insert([0, start]);while(!minHeap.isEmpty()){const[dist, node]= minHeap.extractMin()!;// Module A-1 — always the smallest known distance so farif(visited.has(node))continue;// a shorter path to this node was already finalized visited.add(node);for(const[neighbor, weight]of graph.get(node)??[]){const newDist = dist + weight;if(newDist <(distances.get(neighbor)??Infinity)){ distances.set(neighbor, newDist); minHeap.insert([newDist, neighbor]);// a cheaper route to `neighbor` was just found}}}return distances;}
// Why negative weights break Dijkstra's greedy assumption:// A -> B: weight 5// A -> C: weight 2// C -> B: weight -10//// Dijkstra finalizes distance to B as 5 (via A directly) before ever considering C's// path, because 2 < 5 means C gets processed... but if C -> B costs -10, the true// shortest path to B is 2 + (-10) = -8, much cheaper than the 5 Dijkstra already locked in.