@@ -9,30 +9,58 @@ class JohnsonGraph:
99 def __init__ (self ) -> None :
1010 """
1111 Initializes an empty graph with no edges.
12+ >>> g = JohnsonGraph()
13+ >>> g.edges
14+ []
15+ >>> g.graph
16+ {}
1217 """
1318 self .edges : list [tuple [str , str , int ]] = []
1419 self .graph : dict [str , list [tuple [str , int ]]] = {}
1520
1621 # add vertices for a graph
1722 def add_vertices (self , vertex : str ) -> None :
1823 """
19- Adds a vertex `u` to the graph with an empty adjacency list.
24+ Adds a vertex `vertex` to the graph with an empty adjacency list.
25+ >>> g = JohnsonGraph()
26+ >>> g.add_vertices("A")
27+ >>> g.graph
28+ {'A': []}
2029 """
2130 self .graph [vertex ] = []
2231
2332 # assign weights for each edges formed of the directed graph
2433 def add_edge (self , vertex_a : str , vertex_b : str , weight : int ) -> None :
2534 """
26- Adds a directed edge from vertex `u` to vertex `v` with weight `w`.
35+ Adds a directed edge from vertex `vertex_a`
36+ to vertex `vertex_b` with weight `weight`.
37+ >>> g = JohnsonGraph()
38+ >>> g.add_vertices("A")
39+ >>> g.add_vertices("B")
40+ >>> g.add_edge("A", "B", 5)
41+ >>> g.edges
42+ [('A', 'B', 5)]
43+ >>> g.graph
44+ {'A': [('B', 5)], 'B': []}
2745 """
2846 self .edges .append ((vertex_a , vertex_b , weight ))
2947 self .graph [vertex_a ].append ((vertex_b , weight ))
3048
3149 # perform a dijkstra algorithm on a directed graph
3250 def dijkstra (self , start : str ) -> dict :
3351 """
34- Computes the shortest path from vertex `s`
52+ Computes the shortest path from vertex `start`
3553 to all other vertices using Dijkstra's algorithm.
54+ >>> g = JohnsonGraph()
55+ >>> g.add_vertices("A")
56+ >>> g.add_vertices("B")
57+ >>> g.add_edge("A", "B", 1)
58+ >>> g.dijkstra("A")
59+ {'A': 0, 'B': 1}
60+ >>> g.add_vertices("C")
61+ >>> g.add_edge("B", "C", 2)
62+ >>> g.dijkstra("A")
63+ {'A': 0, 'B': 1, 'C': 3}
3664 """
3765 distances = {vertex : sys .maxsize - 1 for vertex in self .graph }
3866 pq = [(0 , start )]
@@ -52,8 +80,18 @@ def dijkstra(self, start: str) -> dict:
5280 # carry out the bellman ford algorithm for a node and estimate its distance vector
5381 def bellman_ford (self , start : str ) -> dict :
5482 """
55- Computes the shortest path from vertex `s`
56- to all other vertices using the Bellman-Ford algorithm.
83+ Computes the shortest path from vertex `start` to
84+ all other vertices using the Bellman-Ford algorithm.
85+ >>> g = JohnsonGraph()
86+ >>> g.add_vertices("A")
87+ >>> g.add_vertices("B")
88+ >>> g.add_edge("A", "B", 1)
89+ >>> g.bellman_ford("A")
90+ {'A': 0, 'B': 1}
91+ >>> g.add_vertices("C")
92+ >>> g.add_edge("B", "C", 2)
93+ >>> g.bellman_ford("A")
94+ {'A': 0, 'B': 1, 'C': 3}
5795 """
5896 distances = {vertex : sys .maxsize - 1 for vertex in self .graph }
5997 distances [start ] = 0
@@ -73,8 +111,19 @@ def bellman_ford(self, start: str) -> dict:
73111 # or the bellman ford algorithm efficiently
74112 def johnson_algo (self ) -> list [dict ]:
75113 """
76- Computes the shortest paths between
77- all pairs of vertices using Johnson's algorithm.
114+ Computes the shortest paths between
115+ all pairs of vertices using Johnson's algorithm
116+ for a directed graph.
117+ >>> g = JohnsonGraph()
118+ >>> g.add_vertices("A")
119+ >>> g.add_vertices("B")
120+ >>> g.add_vertices("C")
121+ >>> g.add_edge("A", "B", 1)
122+ >>> g.add_edge("B", "C", 2)
123+ >>> g.add_edge("A", "C", 4)
124+ >>> optimal_paths = g.johnson_algo()
125+ >>> optimal_paths
126+ [{'A': 0, 'B': 1, 'C': 3}, {'A': None, 'B': 0, 'C': 2}, {'A': None, 'B': None, 'C': 0}]
78127 """
79128 self .add_vertices ("#" )
80129 for vertex in self .graph :
@@ -95,36 +144,26 @@ def johnson_algo(self) -> list[dict]:
95144 weight + hash_path [vertex_a ] - hash_path [vertex_b ])
96145
97146 self .graph .pop ("#" )
98- self .edges = [
99- (vertex1 , vertex2 , node_weight )
100- for vertex1 , vertex2 , node_weight in self .edges
101- if vertex1 != "#"
102- ]
103147 filtered_edges = []
104148 for vertex1 , vertex2 , node_weight in self .edges :
105- if vertex1 != "#" :
106- filtered_edges .append ((vertex1 , vertex2 , node_weight ))
149+ filtered_edges .append ((vertex1 , vertex2 , node_weight ))
107150 self .edges = filtered_edges
108151
109152 for vertex in self .graph :
110- self .graph [vertex ] = [
111- (vertex2 , node_weight )
112- for vertex1 , vertex2 , node_weight in self .edges
113- if vertex1 == vertex
114- ]
115-
116- filtered_neighbors = []
153+ self .graph [vertex ] = []
117154 for vertex1 , vertex2 , node_weight in self .edges :
118155 if vertex1 == vertex :
119- filtered_neighbors .append ((vertex2 , node_weight ))
120- self .graph [vertex ] = filtered_neighbors
156+ self .graph [vertex ].append ((vertex2 , node_weight ))
121157
122158 distances = []
123159 for vertex1 in self .graph :
124160 new_dist = self .dijkstra (vertex1 )
125161 for vertex2 in self .graph :
126- if new_dist [vertex2 ] < sys .maxsize - 1 :
127- new_dist [vertex2 ] += hash_path [vertex1 ] - hash_path [vertex2 ]
162+ if new_dist [vertex2 ] < sys .maxsize - 1 :
163+ new_dist [vertex2 ] += hash_path [vertex2 ] - hash_path [vertex1 ]
164+ for key in new_dist :
165+ if new_dist [key ] == sys .maxsize - 1 :
166+ new_dist [key ] = None
128167 distances .append (new_dist )
129168 return distances
130169
0 commit comments