Dijkstra’s Algorithm

Dijkstra’s algorithm is a generalization of BFS from unit-cost to weighted graphs. Instead of breadth-first, we’re now “best-first”. Instead of using a queue and always popping the next node in queue, we now use a priority queue and always pop the best node (in terms of distance from source) each time. Instead of using the popped node to push (unvisited) neighbors into the queue, we now use the popped node \(v\) to update neighbors \(u\) if possible.

BFS Dijkstra
used for unweighted graph weighted graph
visit order breadth-first best-first
data structure queue PQ
always pop the next node in queue the best node in PQ
use popped node to push (unvisited) neighbors to queue update neighbors if possible

Standard Implementation with decrease_key

Pseudocode:

d = defaultdict(lambda : infinity) # distance estimate from s to each v
d[s] = 0
PQ = {(s, 0)} # start node; in practice: PQ = {s: 0}
while PQ not empty:
    (v, dist) = PQ.pop() # best distance from s to v is now fixed
    for (v, u, w) in v's outgoing edges:
        if dist + w < d[u]: # can update?
            d[u] = dist + w # new estimate
            PQ.decrease_key(u, d[u]) # in practice: PQ[u] = d[u]    

Alternative Implementation with Duplicates

Pseudocode:

d = defaultdict(lambda : infinity) # distance estimate from s to each v
d[s] = 0
PQ = {(s, 0)} # start node; in practice (heapq): PQ = [(0, s)]
popped = empty_set # black nodes
while PQ not empty:
    (v, dist) = PQ.pop() # could be duplicate pop!
    if v not in popped: # first time v is popped?
        popped.add(v)
        for (v, u, w) in v's outgoing edges:
            if dist + w < d[u]: # can update?
                d[u] = dist + w # new estimate
                PQ.push(u, d[u]) # could be duplicate    

Summary

standard alternative
method decrease_key push duplicates
PQ size \(O(V)\) \(O(E)\)
number of pops exactly \(V\) at most \(E\)
… total pop time \(O(V\log V)\) \(O(E\log E)\)
number of pushes or updates at most \(E\) at most \(E\)
… total push/update time \(O(E\log V)\) \(O(E\log E)\)
total time \(O((V+E)\log V)\) \(O(E\log E)\)