ADV 02 - Implement Dijkstra’s Algorithm
Intro
Dijkstra's algorithm is a widely used algorithm for finding the shortest path in a weighted graph. It starts at the source node, examines adjacent nodes, and updates their tentative distances. It adds the node with the smallest tentative distance to the visited set until the destination node is reached or there are no more unvisited nodes.
Task
Using the given code complete the existing Python code to produce code that works for the example below (same as Week 6 lecture), plus any other (come up with alternative graphs for testing purposes). You need to complete the code where indicated. The code, if working, will output the correct solution for the graph below.
The output from your code should look something like this:
(['O', 'A', 'B', 'D', 'T'], 13)
a list of the nodes which is the lowest cost path, as well as the cost itself.
Python code
from collections import defaultdict
import sys
class Graph():
def __init__(self, size):
self.edges = defaultdict(list) #dictionary of all connected nodes e.g. {'X': ['A', 'B', 'C', 'E'], ...}
self.weights = {} #dictionary of edges and weights e.g. {('X', 'A'): 7, ('X', 'B'): 2, ...}
self.size = size
self.dist = []
for i in range(size):
self.dist.append(sys.maxsize)
self.previous = []
for i in range(size):
self.previous.append(None)
def add_edge(self, from_node, to_node, weight): #bidirectional
self.edges[from_node].append(to_node)
self.edges[to_node].append(from_node)
self.weights[(from_node, to_node)] = weight
self.weights[(to_node, from_node)] = weight
def findSmallestNode(self):
smallest = self.dist[self.getIndex(self.Q[0])]
result = self.getIndex(self.Q[0])
for i in range(len(self.dist)):
if self.dist[i] < smallest:
node = self.unpoppedQ[i]
if node in self.Q:
smallest = self.dist[i]
result = self.getIndex(node)
return result
def getIndex(self, neighbour):
for i in range(len(self.unpoppedQ)):
if neighbour == self.unpoppedQ[i]:
return i
def getPopPosition(self, uNode):
result = 0
for i in range(len(self.Q)):
if self.Q[i] == uNode:
return i
return result
def getUnvisitedNodes(self, uNode):
resultList = []
allNeighbours = self.edges[uNode]
for neighbour in allNeighbours:
if neighbour in self.Q:
resultList.append(neighbour)
return resultList
def dijsktra(self, start, end):
self.Q = []
for key in self.edges:
self.Q.append(key)
for i in range(len(self.Q)):
if self.Q[i] == start:
self.dist[i] = 0
self.unpoppedQ = self.Q[0:]
while self.Q:
u = self.findSmallestNode()
if self.dist[u] == sys.maxsize:
break
if self.unpoppedQ[u] == end:
break
uNode = self.unpoppedQ[u]
### COMPLETE CODE HERE ###
shortest_path = []
shortest_path.insert(0, end)
u = self.getIndex(end)
while self.previous[u] != None:
shortest_path.insert(0, self.previous[u])
u = self.getIndex(self.previous[u])
return shortest_path
graph = Graph(8)
edges = [
('O', 'A', 2),
('O', 'B', 5),
('O', 'C', 4),
('A', 'B', 2),
('A', 'D', 7),
('A', 'F', 12),
('B', 'C', 1),
('B', 'D', 4),
('B', 'E', 3),
('C', 'E', 4),
('D', 'E', 1),
('D', 'T', 5),
('E', 'T', 7),
('F', 'T', 3),
]
for edge in edges:
graph.add_edge(*edge)
print(graph.dijsktra('O', 'T'))