Solution Review: Implementing Dijkstra's
In this lesson, we'll look at a way to implement Dijkstra's Algorithm.
Solution #1: Calculating All Paths
def Dijkstra(graph, src, dst):number_of_nodes = len(graph[0]) # Number of nodes in the graphparent = [-1] * number_of_nodes # Setting up various listsvisited = []unvisited = [i for i in range(number_of_nodes)]distance = [16] * number_of_nodes # The distance list initially has a distance of infinite for all but the source nodedistance[src] = 0shortest_path = [] # This list will have the shortest path at the endcurrent = src # We start with the sourcewhile(len(unvisited)>0):# Visit all neighbors of current and update distancefor i in range(number_of_nodes):if(graph[current][i]>=0 and distance[i] > graph[current][i]+distance[current]):distance[i] = graph[current][i]+distance[current] # Update distanceparent[i] = current # Set new parentunvisited.remove(current) # Move current node from unvisited to vistedvisited.append(current)if(len(unvisited) != 0):current = unvisited[0] # New current node is an unvisited node with the smallest 'distance'for n in unvisited:if(distance[n] < distance[current]):current = ncurr = dst # Some code to get the shortest path from 'parent'shortest_path.append(curr)cost = 0while curr is not src:if parent[curr] == -1: # If there is no path to the source nodereturn([[],-1])cost = cost + graph[curr][parent[curr]] # The cost is the sum of the links in a pathcurr = parent[curr]shortest_path.append(curr)shortest_path.reverse()return([shortest_path, cost])def main():graph = [[0,1,5,-1,-1],[1,0,3,-1,9],[5,3,0,4,-1],[-1,-1,4,0,2],[-1,9,-1,2,0]]src = 0dst = 3print(Dijkstra(graph,src,dst))if __name__ == "__main__":main()
Explanation
Let’s go through this code line by line.
- Lines 1-9: we set up a few variables that are important for the implementation.
- The
number_of_nodes
is the number of nodes in the graph. It’s equivalent to the number of rows/columns of the givengraph
. This variable is not necessary for the algorithm itself, but makes calculating other variables clear and easy. - The
parent
list will map each node to its ‘parent’ or the previous node in the shortest path to the source node. Initialized to-1
. - The
visited
list is initially empty. - The
unvisited
list contains all the nodes in the graph. Since the nodes in our graph are labeled by numbers, this list is simple to generate. - The
distance
list has all the current distances of all the nodes from thesrc
node. Note that all the distances besides the distance of thesrc
node from itself are set to infinity, i.e.,16
. - The
shortest_path
is initialized to an empty list. - The
current
node is set to thesrc
node since we are calculating the shortest paths fromsrc
to the rest of the nodes.
- The
- Lines 11-24: The
while
loop.- We iterate through all of the neighbors of every
current
node. - If the current distance for a node is greater than the distance of the
current
node + the cost of the link between them, its distance is updated and itsparent
is changed tocurrent
. - Once all of the neighbors of a node have been exhausted, the next
current
node is chosen to be an unvisited node with the smallestdistance
. - Steps 1-3 are repeated until the while loop exits when no more nodes are left to visit.
- We iterate through all of the neighbors of every
- Lines 26-34: Calculating the shortest path and the cost. We traverse the
parent
list link by link until a path is generated. Since we start from the destination, the path has to be reversed. While we calculate the path, we also sum up the cost of each link that is traversed.- Example: Assume the source node is
0
. IFparent[2]
has the value1
, the previous node from2
is1
as part of the shortest path to a source. Then, supposeparent[1]
is0
. So the shortest path will turn out to be[2, 1, 0]
.
- Example: Assume the source node is
Solution #2: Stopping When Route to dst
is Calculated
def Dijkstra(graph, src, dst):number_of_nodes = len(graph[0]) # Number of nodes in the graphparent = [-1] * number_of_nodes # Setting up various listsvisited = []unvisited = [i for i in range(number_of_nodes)]distance = [16] * number_of_nodes # The distance list initially has a distance of infinite for all but the source nodedistance[src] = 0shortest_path = [] # This list will have the shortest path at the endcurrent = src # We start with the sourcewhile(len(unvisited)>0):# Visit all neighbors of current and update distancefor i in range(number_of_nodes):if(graph[current][i]>=0 and distance[i] > graph[current][i]+distance[current]):distance[i] = graph[current][i]+distance[current] # Update distanceparent[i] = current # Set new parentif(current == dst):breakunvisited.remove(current) # Move current node from unvisited to vistedvisited.append(current)if(len(unvisited) != 0):current = unvisited[0] # New current node is an unvisited node with the smallest 'distance'for n in unvisited:if(distance[n] < distance[current]):current = ncurr = dst # Some code to get the shortest path from 'parent'shortest_path.append(curr)cost = 0while curr is not src:if parent[curr] == -1: # If there is no path to the source nodereturn([[],-1])cost = cost + graph[curr][parent[curr]] # The cost is the sum of the links in a pathcurr = parent[curr]shortest_path.append(curr)shortest_path.reverse()return([shortest_path, cost])def main():graph = [[0,1,5,-1,-1],[1,0,3,-1,9],[5,3,0,4,-1],[-1,-1,4,0,2],[-1,9,-1,2,0]]src = 0dst = 3print(Dijkstra(graph,src,dst))if __name__ == "__main__":main()
Explanation
This solution differs from the previous one because it exits the while loop as soon as the destination node is visited via the if condition on lines 18 and 19. Since subsequent calculations for the rest of the graph do not change the shortest path to the destination node, there is no need to visit all of them.
In the next lesson, we’ll learn about the Internet protocol!
Create a free account to view this lesson.
Continue your learning journey with a 14-day free trial.
By signing up, you agree to Educative's Terms of Service and Privacy Policy