Skip to content

Commit ae87c5d

Browse files
committed
Finish implementation
But because I make the weight of an edge as the key of the dictionary any graph with more than a single edge with the same weight will yield wrong result. Signed-off-by: Aditya Prasad <[email protected]>
1 parent 3b92778 commit ae87c5d

File tree

1 file changed

+123
-11
lines changed

1 file changed

+123
-11
lines changed

Kruskal's.py

Lines changed: 123 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def __iter__(self):
136136
# values(weights) range from 0 to k.
137137
def counting_sort(weights,max_weight):
138138
# these k+1 counters are made here is used to know how many times each value in range(k+1) (0 to k) repeats
139-
counter=[0]*(k+1)
139+
counter=[0]*(max_weight+1)
140140
for i in weights:
141141
# if you encounter a particular number increment its respective counter
142142
counter[i] += 1
@@ -155,25 +155,137 @@ def counting_sort(weights,max_weight):
155155
# now we have a optimal sorting function in hand, lets sort the list of edges.
156156
# a dictionary with weights of an edge and the vertexes involved in that edge.
157157
vrwght={}
158+
# take every vertex in the graph
158159
for ver1 in the_graph:
159-
print "ver1 = "
160-
print ver1
160+
# take every vertex ver1 is connected to = ver2
161161
for ver2 in ver1.getConnections():
162+
# make the dictionary with the weights and the 2 vertex's involved with the edge (thier key)
162163
vrwght[ver1.connectedTo[ver2]]=[ver1.getId(),ver2.getId()]
163164

165+
print "\nThe edges with thier unsorted weights are"
164166
print vrwght
165-
print vrwght.keys()
166-
print the_graph.getVertices()
167-
print the_graph.getVertices()
168167

168+
temp_weights=vrwght.keys()
169+
counting_sort(temp_weights,max_weight)
170+
171+
sorted_weights={}
172+
for weight in temp_weights:
173+
sorted_weights[weight]=vrwght[weight]
174+
175+
print "\nAfter sorting"
176+
print sorted_weights
177+
178+
179+
# Now step 2 : now we the smallest edge wrt to weight and add it to the MST,
180+
# IF the two nodes associated with the edge belong TO DIFFERENT sets.
181+
# What? well see kruskal's algo for finding the MST is simple,
182+
# we take the graph, remove all the edges and order them based on thier weight
183+
# now we replace all the removed edges back to the "graph" (which we just now plucked clean)
184+
# smallest first. Subject to the condition that adding a edge doesnt cause a CYCLE or LOOP
185+
# to develop, a tree cant have such loops we must avoid them.so we skip them
186+
# so this series of steps explains Kruskal's algorithm:
187+
"""
188+
1. Take all edges in an array and Sort that array (in an ascending order)
189+
2. Take the next (minimum edge), examine its end nodes:
190+
a) If they belong to different sets, merge their sets and add that edge to the tree
191+
b) Otherwise skip the edge
192+
3. Print the tree obtained.
193+
"""
194+
195+
# 2. a) is the method used to check if adding a particular edge will cause a cycle,
196+
# Thus comes the UNION-FIND algorithm :
197+
# Many thanks to David Eppstein of the University of California,
198+
# this is taken from PADS, a library of Python Algorithms and Data Structures
199+
class UnionFind:
200+
"""Union-find data structure.
201+
202+
Each unionFind instance X maintains a family of disjoint sets of
203+
hashable objects, supporting the following two methods:
204+
205+
FIND
206+
- X[item] returns a name for the set containing the given item.
207+
Each set is named by an arbitrarily-chosen one of its members; as
208+
long as the set remains unchanged it will keep the same name. If
209+
the item is not yet part of a set in X, a new singleton set is
210+
created for it.
211+
212+
UNION
213+
- X.union(item1, item2, ...) merges the sets containing each item
214+
into a single larger set. If any item is not yet part of a set
215+
in X, it is added to X as one of the members of the merged set.
216+
"""
169217

170-
171-
218+
def __init__(self):
219+
"""Create a new empty union-find structure."""
220+
self.weights = {}
221+
self.parents = {}
222+
223+
def __getitem__(self, object):
224+
"""Find and return the name of the set containing the object."""
225+
226+
# check for previously unknown object
227+
# if the object is not present in the dictionary make the object itself its own parent and set its weight as 1
228+
if object not in self.parents:
229+
self.parents[object] = object
230+
self.weights[object] = 1
231+
return object
232+
233+
# find path of objects leading to the root
234+
path = [object]
235+
root = self.parents[object]
236+
while root != path[-1]:
237+
path.append(root)
238+
root = self.parents[root]
239+
240+
# compress the path and return
241+
for ancestor in path:
242+
self.parents[ancestor] = root
243+
return root
244+
245+
def __iter__(self):
246+
"""Iterate through all items ever found or unioned by this structure."""
247+
return iter(self.parents)
248+
249+
def union(self, *objects):
250+
"""Find the sets containing the objects and merge them all."""
251+
roots = [self[x] for x in objects]
252+
heaviest = max([(self.weights[r],r) for r in roots])[1]
253+
for r in roots:
254+
if r != heaviest:
255+
self.weights[heaviest] += self.weights[r]
256+
self.parents[r] = heaviest
257+
258+
MST={}
259+
# lets make a union-find instance - this calls init
260+
X=UnionFind()
261+
262+
# sets up the graph - make singleton sets for each vertex
263+
for vertex_key in the_graph.getVertices():
264+
# get all the vertices set up, make them parents of themselfs, each in thier individual sets
265+
# execute FIND for all the vertex's in the_graph
266+
X[the_graph.getVertex(vertex_key)]
267+
268+
# now the UNION.
269+
for weight in sorted_weights:
270+
# here sorted_weights[weight] gives the set of 2 vertex's involved in the that edge
271+
if(X[the_graph.getVertex(sorted_weights[weight][0])]==X[the_graph.getVertex(sorted_weights[weight][1])]):
272+
# if both vertices have the same parent (name) then they are in the same set, so ignore this edge
273+
pass
274+
else:
275+
# else as they belong to different sets we can ADD this edge to the MST (MST will be a subset of sorted_weights)
276+
MST[weight]=sorted_weights[weight]
277+
# and merge the sets these two vertices belong to thus we call union on them.
278+
X.union(the_graph.getVertex(sorted_weights[weight][0]),the_graph.getVertex(sorted_weights[weight][1]))
279+
280+
# thus we have the MST done
281+
282+
print " \n\nIn the graph with these vertex's"
283+
print the_graph.getVertices()
172284

285+
print "\n With these edges between the vertexes given above, we obtain a Minimal Spanning Tree\n"
286+
print MST
173287

174-
175-
176-
288+
print "\n Please note this is a dictionary with key as the weight of the edge and value as the key's of the two vertex's involved in this edge"
177289

178290

179291

0 commit comments

Comments
 (0)