I am trying to find shortest path in a cyclic weighted graph. I have the following recursive function that is able to find shortest path between 2 points if they are not cyclic. For instance my graph looks like this:
graph = {
'A': {'B': 5, 'D': 5, 'E': 7 },
'B': {'C': 4},
'C': {'D': 8, 'E': 2},
'D': {'C': 8, 'E': 6},
'E': {'B': 3}
}
And now my find shortestRoute function looks like this
def findShortestRoute(self, start, end , weight, shortestRoute):
# sys.setrecursionlimit(10000)
visited = []
# Check if start and end nodes exists in route table
if start in self.routesTable and end in self.routesTable:
visited.append(start) # mark start to visited
for adj in self.routesTable[start]:
if(adj == end or adj not in visited):
weight += self.routesTable[start][adj]
'''
If destination matches, we compare
weight of this route to shortest route
so far, and make appropriate switch
'''
if adj == end:
if shortestRoute == 0 or weight < shortestRoute:
shortestRoute = weight
visited.remove(start)
return shortestRoute
'''
If destination does not match, and
destination node has not yet been visited,
we recursively traverse destination node
'''
if adj not in visited:
shortestRoute = self.findShortestRoute(adj, end, weight, shortestRoute)
weight -= self.routesTable[start][adj]
else:
return "No such route exists"
if start in visited:
visited.remove(start)
return shortestRoute
Now for non-cyclic cases if I do something like
findShortestRoute('A', 'C', 0, 0)
this will return 9 which is what expected. However, if I do something like this findShortestRoute('B', 'B', 0, 0)
The function will reach stack overflow. however, since the graph is cyclic there is a way to start from B and get back to B. In this case B-C-E-B which weights 9. But my function is reaching maximum recursion. I would really appreciate if someone can help me with this. Thanks in advance
Your problem is that you do not pass the visited
list through your recursion, so your algorithm gets stuck in cycles. If you pass down the predecessors nodes you can detect cycles and return if you hit one.
Below is how I would change your code to achieve this:
def findShortestRoute(start, end , weight, shortestRoute, visited, routesTable):
# sys.setrecursionlimit(10000)
# Check if start and end nodes exists in route table
if start in routesTable and end in routesTable:
if start in visited:
return 99999
visited.append(start) # mark start to visited
for adj in routesTable[start]:
if(adj == end or adj not in visited):
weight += routesTable[start][adj]
'''
If destination matches, we compare
weight of this route to shortest route
so far, and make appropriate switch
'''
if adj == end:
if shortestRoute == 0 or weight < shortestRoute:
shortestRoute = weight
visited.remove(start)
return shortestRoute
'''
If destination does not match, and
destination node has not yet been visited,
we recursively traverse destination node
'''
if adj not in visited:
shortestRoute = findShortestRoute(adj, end, weight, shortestRoute, visited, routesTable)
weight -= routesTable[start][adj]
else:
return "No such route exists"
return shortestRoute
graph = {'A': {'B': 5, 'D': 5, 'E': 7 },'B': {'C': 4},'C': {'D': 8, 'E': 2},'D': {'C': 8, 'E': 6},'E': {'B': 3}}
print(findShortestRoute('B', 'B', 0, 0, [], graph))