Skip to content

Commit 11bfe18

Browse files
committed
Implementation of Johnson Graph Algorithm
1 parent 6e24935 commit 11bfe18

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

graphs/johnson_graph.py

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from collections import deque
2+
import heapq
3+
import sys
4+
5+
#First implementation of johnson algorithm
6+
class JohnsonGraph:
7+
def __init__(self):
8+
self.edges = []
9+
self.graph = {}
10+
11+
#add vertices for a graph
12+
def add_vertices(self, u):
13+
self.graph[u] = []
14+
15+
#assign weights for each edges formed of the directed graph
16+
def add_edge(self, u, v, w):
17+
self.edges.append((u, v, w))
18+
self.graph[u].append((v,w))
19+
20+
#perform a dijkstra algorithm on a directed graph
21+
def dijkstra(self, s):
22+
no_v = len(self.graph)
23+
distances = {vertex: sys.maxsize-1 for vertex in self.graph}
24+
pq = [(0,s)]
25+
26+
distances[s] = 0
27+
while pq:
28+
weight, v = heapq.heappop(pq)
29+
30+
if weight > distances[v]:
31+
continue
32+
33+
for node, w in self.graph[v]:
34+
if distances[v]+w < distances[node]:
35+
distances[node] = distances[v]+w
36+
heapq.heappush(pq, (distances[node], node))
37+
return distances
38+
39+
#carry out the bellman ford algorithm for a node and estimate its distance vector
40+
def bellman_ford(self, s):
41+
no_v = len(self.graph)
42+
distances = {vertex: sys.maxsize-1 for vertex in self.graph}
43+
distances[s] = 0
44+
45+
for u in self.graph:
46+
for u, v, w in self.edges:
47+
if distances[u] != sys.maxsize-1 and distances[u]+w<distances[v]:
48+
distances[v] = distances[u]+w
49+
50+
return distances
51+
52+
#perform the johnson algorithm to handle the negative weights that could not be handled by either the dijkstra
53+
#or the bellman ford algorithm efficiently
54+
def johnson_algo(self):
55+
56+
self.add_vertices("#")
57+
for v in self.graph:
58+
if v != "#":
59+
self.add_edge("#", v, 0)
60+
61+
n = self.bellman_ford("#")
62+
63+
for i in range(len(self.edges)):
64+
u, v, weight = self.edges[i]
65+
self.edges[i] = (u, v, weight + n[u] - n[v])
66+
67+
self.graph.pop("#")
68+
self.edges = [(u, v, w) for u, v, w in self.edges if u != "#"]
69+
70+
for u in self.graph:
71+
self.graph[u] = [(v, weight) for x, v, weight in self.edges if x == u]
72+
73+
distances = []
74+
for u in self.graph:
75+
new_dist = self.dijkstra(u)
76+
for v in self.graph:
77+
if new_dist[v] < sys.maxsize-1:
78+
new_dist[v] += n[v] - n[u]
79+
distances.append(new_dist)
80+
return distances
81+
82+
g = JohnsonGraph()
83+
#this a complete connected graph
84+
g.add_vertices("A")
85+
g.add_vertices("B")
86+
g.add_vertices("C")
87+
g.add_vertices("D")
88+
g.add_vertices("E")
89+
90+
g.add_edge("A", "B", 1)
91+
g.add_edge("A", "C", 3)
92+
g.add_edge("B", "D", 4)
93+
g.add_edge("D", "E", 2)
94+
g.add_edge("E", "C", -2)
95+
96+
97+
optimal_paths = g.johnson_algo()
98+
print("Print all optimal paths of a graph using Johnson Algorithm")
99+
for i, row in enumerate(optimal_paths):
100+
print(f"{i}: {row}")

0 commit comments

Comments
 (0)