11# Author: OMKAR PATHAK
22# Created On: 12th August 2017
3+ from collections import defaultdict
4+
35
46class Graph (object ):
57 def __init__ (self ):
6- self .graph = {}
8+ self .graph = defaultdict ( list )
79 self .count = 0
810
911 def print_graph (self ):
1012 ''' for printing the contents of the graph '''
11- for i in self .graph :
12- print (i ,'->' ,' -> ' .join ([str (j ) for j in self .graph [i ]]))
13+ for i in self .graph :
14+ print (i , '->' , ' -> ' .join ([str (j ) for j in self .graph [i ]]))
1315
1416 def add_edge (self , from_vertex , to_vertex ):
1517 ''' function to add an edge in the graph '''
1618 # check if vertex is already present
17- if from_vertex in self .graph .keys ():
18- self .graph [from_vertex ].append (to_vertex )
19- self .count += 1
20- else :
21- self .graph [from_vertex ] = [to_vertex ]
22- self .graph [to_vertex ] = []
23- self .count += 1
19+ self .graph [from_vertex ].append (to_vertex )
20+ self .count += 1
2421
2522 def get_code (self ):
26- ''' returns the code for the current class '''
23+ """ returns the code for the current class """
2724 import inspect
2825 return inspect .getsource (Graph )
2926
27+
28+ class WeightedGraph :
29+ """
30+ A graph with a numerical value (weight) on edges
31+ """
32+ def __init__ (self ):
33+ self .edges_weighted = []
34+ self .vertexes = set ()
35+
36+ def add_edge (self , u , v , weight ):
37+ """
38+ :param u: from vertex - type : integer
39+ :param v: to vertex - type : integer
40+ :param weight: weight of the edge - type : numeric
41+ """
42+ edge = ((u , v ), weight )
43+ self .edges_weighted .append (edge )
44+ self .vertexes .update ((u , v ))
45+
46+ def print_graph (self ):
47+ for (u , v ), weight in self .edges_weighted :
48+ print ("%d -> %d weight: %d" % (u , v , weight ))
49+
50+ def _set_of (self , vertex ):
51+ for tree in self .forest :
52+ if vertex in tree :
53+ return tree
54+ return None
55+
56+ def _union (self , u_set , v_set ):
57+ self .forest .remove (u_set )
58+ self .forest .remove (v_set )
59+ self .forest .append (v_set + u_set )
60+
61+ def kruskal_mst (self ):
62+ """
63+ Kruskal algorithm for finding the minimum spanning tree of a weighted graph.
64+ This version use a union-find data structure.
65+ More detailed info here: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
66+ Author: Michele De Vita <mik3dev@gmail.com>
67+ """
68+ # sort by weight
69+ self .edges_weighted .sort (key = lambda pair : pair [1 ])
70+ edges_explored = []
71+ self .forest = [[v ] for v in self .vertexes ]
72+ for (u , v ), weight in self .edges_weighted :
73+ u_set , v_set = self ._set_of (u ), self ._set_of (v )
74+ if u_set != v_set :
75+ self ._union (u_set , v_set )
76+ edges_explored .append (((u , v ), weight ))
77+ return edges_explored
78+
79+ @staticmethod
80+ def kruskal_complexity ():
81+ return '''Worst case: O(E log(V)) where E in the number of edges and V the number of vertexes'''
82+
83+ @classmethod
84+ def kruskal_code (cls ):
85+ import inspect
86+ return inspect .getsource (cls .kruskal_mst )
87+
88+
3089class TopologicalSort (Graph ):
3190 def topological_sort (self ):
3291 ''' function for sorting graph elements using topological sort '''
33- visited = [False ] * self .count # Marking all vertices as not visited
34- stack = [] # Stack for storing the vertex
92+ visited = [False ] * self .count # Marking all vertices as not visited
93+ stack = [] # Stack for storing the vertex
3594 for vertex in range (self .count ):
3695 # Call the recursive function only if not visited
37- if visited [vertex ] == False :
96+ if not visited [vertex ]:
3897 self .topological_sort_rec (vertex , visited , stack )
3998
4099 return stack
@@ -53,22 +112,23 @@ def topological_sort_rec(self, vertex, visited, stack):
53112 return
54113
55114 # Push current vertex to stack which stores the result
56- stack .insert (0 ,vertex )
115+ stack .insert (0 , vertex )
57116
58117 def get_code (self ):
59118 ''' returns the code for the current class '''
60119 import inspect
61120 return inspect .getsource (TopologicalSort )
62121
122+
63123class CheckCycleDirectedGraph (object ):
64124 def __init__ (self ):
65125 self .graph = {}
66126 self .count = 0
67127
68128 def print_graph (self ):
69129 ''' for printing the contents of the graph '''
70- for i in self .graph :
71- print (i ,'->' ,' -> ' .join ([str (j ) for j in self .graph [i ]]))
130+ for i in self .graph :
131+ print (i , '->' , ' -> ' .join ([str (j ) for j in self .graph [i ]]))
72132
73133 def add_edge (self , from_vertex , to_vertex ):
74134 ''' function to add an edge in the graph '''
@@ -114,18 +174,19 @@ def get_code(self):
114174 import inspect
115175 return inspect .getsource (CheckCycleDirected )
116176
177+
117178class CheckCycleUndirectedGraph (object ):
118179 def __init__ (self ):
119180 self .graph = {}
120181 self .count = 0
121182
122183 def print_graph (self ):
123184 ''' for printing the contents of the graph '''
124- for i in self .graph :
125- print (i ,'->' ,' -> ' .join ([str (j ) for j in self .graph [i ]]))
185+ for i in self .graph :
186+ print (i , '->' , ' -> ' .join ([str (j ) for j in self .graph [i ]]))
126187
127188 def add_edge (self , fromVertex , toVertex ):
128- ''' for adding the edge beween two vertices '''
189+ ''' for adding the edge between two vertices '''
129190 # check if vertex is already present,
130191 if fromVertex in self .graph .keys () and toVertex in self .graph .keys ():
131192 self .graph [fromVertex ].append (toVertex )
@@ -137,7 +198,7 @@ def add_edge(self, fromVertex, toVertex):
137198
138199 def check_cycle (self ):
139200 ''' This function will return True if graph is cyclic else return False '''
140- visited = [False ] * len (self .graph ) # Marking all vertices as not visited
201+ visited = [False ] * len (self .graph ) # Marking all vertices as not visited
141202 for vertex in range (len (self .graph )):
142203 # Call the recursive function only if not visited
143204 if visited [vertex ] == False :
0 commit comments