dijkstra’s algorithm implemented with a min-heap
TRANSCRIPT
Dijkstra’s Algorithm Implemented with a Min-Heap
https://courses.missouristate.edu/anthonyclark/325
Outline
Topics and Learning Objectives• Look at Dijkstra’s Algorithm when implemented using a heap
Assessments• None
def dijkstras_heap(adjacency_list, start_vertex):"""Dijkstra's Algorithm implemented with all vertices placed in a heap.
This version of Dijkstra's Algorithm has a running time of O(m lg n)."""
n = len(adjacency_list)
path_lengths = {v: inf for v in adjacency_list}predecessors = {v: None for v in adjacency_list}
path_lengths[start_vertex] = 0predecessors[start_vertex] = None
found = set()vertex_min_heap = [(path_lengths[start_vertex], start_vertex)]
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap, (path_lengths[vto], vto))
return path_lengths, predecessors
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap, (path_lengths[vto], vto))
def print_path(end_vertex, predecessors):
path = [end_vertex]pred = predecessors[end_vertex]
while pred is not None:
path.append(pred)pred = predecessors[pred]
print(" -> ".join([str(v) for v in reversed(path)]))
Dijkstra’s Algorithm Correctness
Theorem:• Dijkstra’s algorithm will find the shortest path from the start vertex to
every other vertex on any graph with non-negative weights.
Proof using a loop invariant. Loop predicate:• At the start of each iteration of the while loop, the shortest path has
been found for every vertex in the found set
Initialization
• Initially, the found set is empty. So, the invariant is trivially true.
Loop predicate/invariant: At the start of each iteration of the while loop, the shortest path has been found for every vertex in the found set
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap,(path_lengths[vto], vto))
Maintenance (1)
• Assume all previous iterations have produced the correct shortest path for all vertices in the found set.• For purposes of a contradiction,
assume that when a vertex u is added to the found set its path length is not optimal.• At the time u is found we must
have some path to u
Loop predicate/invariant: At the start of each iteration of the while loop, the shortest path has been found for every vertex in the found set
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap,(path_lengths[vto], vto))
Maintenance (1)
• Assume all previous iterations have produced the correct shortest path for all vertices in the found set.• For purposes of a contradiction,
assume that when a vertex u is added to the found set its path length is not optimal.• At the time u is found we must
have some path to u
Loop predicate/invariant: At the start of each iteration of the while loop, the shortest path has been found for every vertex in the found set
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap,(path_lengths[vto], vto))
Maintenance (1)
• For purposes of a contradiction, assume that when a vertex u is added to the found set its path length is not optimal.• At the time u is found we must have
some path to u• To have a shorter path to u, it must
go through some vertex k not in found.• But a shorter path going through k,
means that k must have been chosen before u.
Loop predicate/invariant: At the start of each iteration of the while loop, the shortest path has been found for every vertex in the found set
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap,(path_lengths[vto], vto))
Termination
• The loop terminates when all vertices have been added to the found set.• Given the loop invariant the
shortest path to all vertices have been calculated.
Loop predicate/invariant: At the start of each iteration of the while loop, the shortest path has been found for every vertex in the found set
while len(found) != n:vfrom_length, vfrom = heappop(vertex_min_heap)found.add(vfrom)
for vto, weight in adjacency_list[vfrom]:path_length = vfrom_length + weightif path_length < path_lengths[vto]:
path_lengths[vto] = path_lengthpredecessors[vto] = vfrom
heappush(vertex_min_heap,(path_lengths[vto], vto))