Search code examples
python-3.xalgorithmgraphadjacency-listweighted-graph

Minimum cost path on a undirected weighted graph using an adjacency list


I have implemented a minimum cost path function to my undirected weighted graph using an adjacency list. My approach of the minimum cost path function does not use a priority queue. My goal is to calculate and display the shortest path from a starting node.

I'm able to calculate the shortest path starting at node A, however, the order of the nodes does not match the order of the nodes. Would it be better if I implemented a priority queue? Any help would be appreciated!

The minimum cost paths starting at A 
 Expected B(4) C(12) D(19) E(21) F(11) G(9) H(8) I(14) J(inf) 

 Actually B(4) H(8) C(12) G(9) I(14) D(19) F(11) E(21)
The adjacency list:
A- {'B': 4, 'H': 8}
B- {'A': 4, 'C': 8, 'H': 11}
C- {'B': 8, 'D': 7, 'F': 4, 'I': 2}
D- {'C': 7, 'E': 9, 'F': 14}
E- {'D': 9, 'F': 10}
F- {'C': 4, 'D': 14, 'E': 10, 'G': 2}
G- {'F': 2, 'H': 1, 'I': 6}
H- {'A': 8, 'B': 11, 'G': 1, 'I': 7}
I- {'C': 2, 'G': 6, 'H': 7}
J- {}

My code

class WGraph:
    def __init__(self, size=10):
        self.size = 10
        self.nodeList = {}
        self.adjacencyMatrix = [[0] * size for i in range(size)]  # initialize matrix

    def addNode(self, name):
        """Adds node to adjacency list"""
        self.nodeList[name] = {}

    def addEdge(self, startIndex, endIndex, weight):
        """Add edges for adjacency list and matrix"""
        self.nodeList[startIndex][endIndex] = weight
        self.nodeList[endIndex][startIndex] = weight

        index1 = list(self.nodeList.keys()).index(startIndex)
        index2 = list(self.nodeList.keys()).index(endIndex)
        self.adjacencyMatrix[index1][index2] = weight

    def displayAdjacency(self):
        """Displays adjacency list with edges and weight"""
        for node in self.nodeList:
            print(node + "- " + str(self.nodeList[node]))


    def minCostPaths(self, vertex):
        visited = {vertex: 0}
        queue = [(vertex, 0)]
        while queue:
            node, cost = queue.pop(0)
            for neighbor in self.nodeList[node]:
                if neighbor not in visited or cost + self.nodeList[node][neighbor] < visited[neighbor]:
                    visited[neighbor] = cost + self.nodeList[node][neighbor]
                    queue.append((neighbor, cost + self.nodeList[node][neighbor]))
        output = ""
        for node in visited:
            if node != vertex:
                output += f"{node}({visited[node]}) "
        return output[:-2] + ")"


# Driver Code
graph = WGraph()

graph.addNode('A')
graph.addNode('B')
graph.addNode('C')
graph.addNode('D')
graph.addNode('E')
graph.addNode('F')
graph.addNode('G')
graph.addNode('H')
graph.addNode('I')
graph.addNode('J')

graph.addEdge('A', 'B', 4)
graph.addEdge('A', 'H', 8)
graph.addEdge('B', 'C', 8)
graph.addEdge('B', 'H', 11)
graph.addEdge('C', 'D', 7)
graph.addEdge('C', 'F', 4)
graph.addEdge('C', 'I', 2)
graph.addEdge('D', 'E', 9)
graph.addEdge('D', 'F', 14)
graph.addEdge('E', 'F', 10)
graph.addEdge('F', 'G', 2)
graph.addEdge('G', 'H', 1)
graph.addEdge('G', 'I', 6)
graph.addEdge('H', 'I', 7)

graph.displayAdjacency()

print("The minimum cost paths starting at A ")
print(" Expected B(4) C(12) D(19) E(21) F(11) G(9) H(8) I(14) J(inf) ")
print(" Actually " + graph.minCostPaths('A'), end="\n")

Solution

  • In your minCostPaths() function, you need to get the list of vertices from self.nodeList, not from visited. The order of BFS traversal is stored in visited, which isn't the ordering you need.

            output = ""
            for node in self.nodeList:
                if node != vertex:
                    output += f"{node}({visited.get(node, 'inf')}) "
            return output[:-2] + ")"
    

    Output:

    The minimum cost paths starting at A 
     Expected B(4) C(12) D(19) E(21) F(11) G(9) H(8) I(14) J(inf) 
     Actually B(4) C(12) D(19) E(21) F(11) G(9) H(8) I(14) J(inf)