Skip to content

Commit 0c736b2

Browse files
author
Hamid Gasmi
committed
#188 is refactored to make the graph class more general
1 parent 4ba0ad2 commit 0c736b2

File tree

1 file changed

+23
-28
lines changed

1 file changed

+23
-28
lines changed

09-problems/graph-algorithms-in-genome-sequencing/eulerian_cycle.py

+23-28
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
import sys
2+
from collections import namedtuple
23

3-
class Eulerian_Graph:
4+
Node_Degree = namedtuple('Node_Degree', ['vertex_no', 'in_degree', 'out_degree'])
5+
6+
class Graph:
47
def __init__(self, edges):
58

69
self._build_graph(edges)
7-
8-
self._is_eulerian_graph()
910

1011
def _build_graph(self, edges):
1112

1213
self.nodes = []
1314
self.adjacency_list = []
1415
self.reversed_adjacency_list = []
15-
self.edges_counts = 0
16-
node_label_dict = dict()
1716

17+
node_label_dict = dict()
1818
for edge in edges:
1919
(start_vertex_label, end_vertices_labels) = edge.split(' -> ')
2020

2121
start_vertex_no = self._get_node_no(start_vertex_label, node_label_dict)
2222

2323
self.adjacency_list[start_vertex_no] = [self._get_node_no(label, node_label_dict) for label in end_vertices_labels.split(',')]
24-
self.edges_counts += len(self.adjacency_list[start_vertex_no])
2524

2625
for a in self.adjacency_list[start_vertex_no]:
2726
self.reversed_adjacency_list[a].append(start_vertex_no)
@@ -40,7 +39,7 @@ def _get_node_no(self, label, node_label_dict):
4039

4140
return node_no
4241

43-
def _is_balanced(self):
42+
def find_unbalanced_vertices(self):
4443

4544
# 1. Compute in_degree for each vertex
4645
in_degree = [0 for _ in range(len(self.adjacency_list))]
@@ -49,18 +48,16 @@ def _is_balanced(self):
4948
in_degree[v] += 1
5049

5150
# 2. Compare in_degree vs. out_degree of each vertex
52-
balanced = True
5351
u = 0
54-
self.balanced = ""
52+
self.unbalanced_vertices = []
5553
while u < len(self.adjacency_list):
5654
if in_degree[u] != len(self.adjacency_list[u]):
57-
balanced = False
58-
break
55+
self.unbalanced_vertices.append(Node_Degree(u, in_degree[u], len(self.adjacency_list[u])))
5956

6057
u += 1
61-
62-
return balanced
6358

59+
return self.unbalanced_vertices
60+
6461
def explore(self, v, adj, postOrderVisits):
6562
self.visited[v] = True
6663
for a in adj[v]:
@@ -76,34 +73,30 @@ def dfs(self, adj, postOrderVisits):
7673
if not self.visited[v]:
7774
self.explore(v, adj, postOrderVisits)
7875

79-
def strongly_connected_components_number(self):
76+
def find_strongly_connected_components(self):
8077

8178
postOrderVisits = []
8279
self.dfs(self.reversed_adjacency_list, postOrderVisits)
8380
self.visited = [ False for _ in range(len(self.nodes)) ]
84-
aSCCList = []
81+
self.strongly_connected_components = []
8582
for i in range(len(postOrderVisits) - 1, -1, -1):
8683
v = postOrderVisits[i]
8784
if not self.visited[v]:
8885
aSCC = []
8986
self.explore(v, self.adjacency_list, aSCC)
90-
aSCCList.append(aSCC)
87+
self.strongly_connected_components.append(aSCC)
9188

92-
return aSCCList
93-
94-
def _is_strongly_connected(self):
95-
96-
aSCCList = self.strongly_connected_components_number()
97-
98-
return len(aSCCList) == 1
89+
return self.strongly_connected_components
9990

10091
def _is_eulerian_graph(self):
10192

10293
# 1. Is balanced
103-
#assert(self._is_balanced())
94+
self.find_unbalanced_vertices()
95+
assert(len(self.unbalanced_vertices) == 0)
10496

10597
# 2. Is strongly connected
106-
#assert(self._is_strongly_connected())
98+
self.find_strongly_connected_components()
99+
assert(len(self.strongly_connected_components) == 1)
107100

108101
return True
109102

@@ -129,6 +122,8 @@ def form_cycle(self, start, cycle, visited_edge_indexes, unvisited_edge_node_dic
129122
return -1 if len(unvisited_edge_node_dict) == 0 else next(iter(unvisited_edge_node_dict.values()))
130123

131124
def eulerian_cycle(self):
125+
126+
assert(self._is_eulerian_graph())
132127

133128
cycle = []
134129
visited_edge_indexes = [-1 for _ in range(len(self.nodes))]
@@ -152,11 +147,11 @@ def eulerian_cycle(self):
152147

153148
new_start_pos_in_cycle = self.form_cycle(new_start, cycle, visited_edge_indexes, unvisited_edge_node_dict)
154149

155-
return '->'.join([ self.nodes[node] for node in cycle])
150+
return cycle
156151

157152
if __name__ == "__main__":
158153
edges = sys.stdin.read().strip().splitlines()
159154

160-
eulerian_graph = Eulerian_Graph(edges)
155+
eulerian_graph = Graph(edges)
161156

162-
print(eulerian_graph.eulerian_cycle())
157+
print('->'.join( [ eulerian_graph.nodes[node] for node in eulerian_graph.eulerian_cycle() ] ))

0 commit comments

Comments
 (0)