From aa0903fbe5df7d64578d43eea17a3ba460bf122c Mon Sep 17 00:00:00 2001 From: Nitisha Bharathi <30657775+nitishabharathi@users.noreply.github.com> Date: Fri, 22 May 2020 16:15:30 +0530 Subject: [PATCH 01/14] added Boruvka's MST algorithm --- graphs/minimum_spanning_tree_boruvka.py | 183 ++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 graphs/minimum_spanning_tree_boruvka.py diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py new file mode 100644 index 000000000000..f13601c105e3 --- /dev/null +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -0,0 +1,183 @@ +class Graph: + """ + Data structure to store graphs (based on adjacency lists) + """ + + def __init__(self): + + self.num_vertices = 0 + self.num_edges = 0 + self.adjacency = {} + + def add_vertex(self, vertex): + """ + Adds a vertex to the graph + + """ + if vertex not in self.adjacency: + self.adjacency[vertex] = {} + self.num_vertices += 1 + + def add_edge(self, head, tail, weight): + """ + Adds an edge to the graph + + """ + + self.add_vertex(head) + self.add_vertex(tail) + + if head == tail: + return + + self.adjacency[head][tail] = weight + self.adjacency[tail][head] = weight + + def distinct_weight(self): + edges = self.get_edges() + for edge in edges: + head, tail, weight = edge + edges.remove((tail, head, weight)) + for i in range(len(edges)): + edges[i] = list(edges[i]) + + edges.sort(key=lambda e: e[2]) + for i in range(len(edges) - 1): + if edges[i][2] >= edges[i + 1][2]: + edges[i + 1][2] = edges[i][2] + 1 + for edge in edges: + head, tail, weight = edge + self.adjacency[head][tail] = weight + self.adjacency[tail][head] = weight + + def __str__(self): + """ + Returns string representation of the graph + """ + string = "" + for tail in self.adjacency: + for head in self.adjacency[tail]: + weight = self.adjacency[head][tail] + string += "%d -> %d == %d\n" % (head, tail, weight) + return string + + def get_edges(self): + """ + Returna all edges in the graph + """ + output = [] + for tail in self.adjacency: + for head in self.adjacency[tail]: + output.append((tail, head, self.adjacency[head][tail])) + return output + + def get_vertices(self): + """ + Returns all vertices in the graph + """ + return self.adjacency.keys() + + @staticmethod + def build(vertices=[], edges=[]): + """ + Builds a graph from the given set of vertices and edges + + """ + g = Graph() + for vertex in vertices: + g.add_vertex(vertex) + for edge in edges: + g.add_edge(*edge) + return g + + class UnionFind(object): + """ + """ + + def __init__(self): + self.parent = {} + self.rank = {} + + def __len__(self): + return len(self.parent) + + def make_set(self, item): + if item in self.parent: + return self.find(item) + + self.parent[item] = item + self.rank[item] = 0 + return item + + def find(self, item): + if item not in self.parent: + return self.make_set(item) + if item != self.parent[item]: + self.parent[item] = self.find(self.parent[item]) + return self.parent[item] + + def union(self, item1, item2): + root1 = self.find(item1) + root2 = self.find(item2) + + if root1 == root2: + return root1 + + if self.rank[root1] > self.rank[root2]: + self.parent[root2] = root1 + return root1 + + if self.rank[root1] < self.rank[root2]: + self.parent[root1] = root2 + return root2 + + if self.rank[root1] == self.rank[root2]: + self.rank[root1] += 1 + self.parent[root2] = root1 + return root1 + + def boruvka_mst(graph): + """ + Implementation of Boruvka's algorithm + """ + num_components = graph.num_vertices + + union_find = Graph.UnionFind() + mst_edges = [] + while num_components > 1: + cheap_edge = {} + for vertex in graph.get_vertices(): + cheap_edge[vertex] = -1 + + edges = graph.get_edges() + for edge in edges: + head, tail, weight = edge + edges.remove((tail, head, weight)) + for edge in edges: + head, tail, weight = edge + set1 = union_find.find(head) + set2 = union_find.find(tail) + if set1 != set2: + if cheap_edge[set1] == -1 or cheap_edge[set1][2] > weight: + cheap_edge[set1] = [head, tail, weight] + + if cheap_edge[set2] == -1 or cheap_edge[set2][2] > weight: + cheap_edge[set2] = [head, tail, weight] + for vertex in cheap_edge: + if cheap_edge[vertex] != -1: + head, tail, weight = cheap_edge[vertex] + if union_find.find(head) != union_find.find(tail): + union_find.union(head, tail) + mst_edges.append(cheap_edge[vertex]) + num_components = num_components - 1 + mst = Graph.build(edges=mst_edges) + return mst + + +g = Graph() +g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], + [0, 3, 1], [1, 2, 1], [2, 3, 1]]) + +g.distinct_weight() +bg = Graph.boruvka_mst(g) +print(bg) From 997ae388a3db56fff90a5875f5f638a67dd7c794 Mon Sep 17 00:00:00 2001 From: Nitisha Bharathi <30657775+nitishabharathi@users.noreply.github.com> Date: Fri, 22 May 2020 20:27:56 +0530 Subject: [PATCH 02/14] Add files via upload --- graphs/minimum_spanning_tree_boruvka.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index f13601c105e3..1a98c782e063 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -34,6 +34,11 @@ def add_edge(self, head, tail, weight): self.adjacency[tail][head] = weight def distinct_weight(self): + ''' + For Boruvks's algorithm the weights should be distinct + Converts the weights to be distinct + + ''' edges = self.get_edges() for edge in edges: head, tail, weight = edge @@ -92,6 +97,7 @@ def build(vertices=[], edges=[]): class UnionFind(object): """ + Disjoint set Union and Find for Boruvka's algorithm """ def __init__(self): @@ -139,6 +145,18 @@ def union(self, item1, item2): def boruvka_mst(graph): """ Implementation of Boruvka's algorithm + >>> g = Graph() + >>> g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], + [0, 3, 1], [1, 2, 1], [2, 3, 1]]) + >>> g.distinct_weight() + >>> Graph.boruvka_mst(g) + 1 -> 0 == 1 + 2 -> 0 == 2 + 3 -> 0 == 3 + 0 -> 1 == 1 + 0 -> 2 == 2 + 0 -> 3 == 3 + """ num_components = graph.num_vertices From a5d1c9203c770e2c2a792520f1fb256d51164853 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 22 May 2020 14:58:50 +0000 Subject: [PATCH 03/14] fixup! Format Python code with psf/black push --- graphs/minimum_spanning_tree_boruvka.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 1a98c782e063..59fe12a78dab 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -34,11 +34,11 @@ def add_edge(self, head, tail, weight): self.adjacency[tail][head] = weight def distinct_weight(self): - ''' + """ For Boruvks's algorithm the weights should be distinct Converts the weights to be distinct - ''' + """ edges = self.get_edges() for edge in edges: head, tail, weight = edge @@ -193,8 +193,7 @@ def boruvka_mst(graph): g = Graph() -g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], - [0, 3, 1], [1, 2, 1], [2, 3, 1]]) +g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], [0, 3, 1], [1, 2, 1], [2, 3, 1]]) g.distinct_weight() bg = Graph.boruvka_mst(g) From 7c1e415cf081fbbefcab5bcf4f535cb73045534d Mon Sep 17 00:00:00 2001 From: Nitisha Bharathi <30657775+nitishabharathi@users.noreply.github.com> Date: Fri, 22 May 2020 20:54:46 +0530 Subject: [PATCH 04/14] Updated Boruvka with doctest --- graphs/minimum_spanning_tree_boruvka.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 59fe12a78dab..1ef13b24200e 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -146,16 +146,16 @@ def boruvka_mst(graph): """ Implementation of Boruvka's algorithm >>> g = Graph() - >>> g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], - [0, 3, 1], [1, 2, 1], [2, 3, 1]]) + >>> g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1],[2, 3, 1]]) >>> g.distinct_weight() - >>> Graph.boruvka_mst(g) + >>> bg = Graph.boruvka_mst(g) + >>> print(bg) 1 -> 0 == 1 2 -> 0 == 2 - 3 -> 0 == 3 0 -> 1 == 1 0 -> 2 == 2 - 0 -> 3 == 3 + 3 -> 2 == 3 + 2 -> 3 == 3 """ num_components = graph.num_vertices @@ -190,11 +190,3 @@ def boruvka_mst(graph): num_components = num_components - 1 mst = Graph.build(edges=mst_edges) return mst - - -g = Graph() -g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1], [0, 3, 1], [1, 2, 1], [2, 3, 1]]) - -g.distinct_weight() -bg = Graph.boruvka_mst(g) -print(bg) From fcb9f61393c0cd89aea95b65d635f4b318ac099c Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 22 May 2020 15:25:13 +0000 Subject: [PATCH 05/14] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 2bb18897044f..935755de6ff5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -246,6 +246,7 @@ * [Greedy Best First](https://github.com/TheAlgorithms/Python/blob/master/graphs/greedy_best_first.py) * [Kahns Algorithm Long](https://github.com/TheAlgorithms/Python/blob/master/graphs/kahns_algorithm_long.py) * [Kahns Algorithm Topo](https://github.com/TheAlgorithms/Python/blob/master/graphs/kahns_algorithm_topo.py) + * [Minimum Spanning Tree Boruvka](https://github.com/TheAlgorithms/Python/blob/master/graphs/minimum_spanning_tree_boruvka.py) * [Minimum Spanning Tree Kruskal](https://github.com/TheAlgorithms/Python/blob/master/graphs/minimum_spanning_tree_kruskal.py) * [Minimum Spanning Tree Prims](https://github.com/TheAlgorithms/Python/blob/master/graphs/minimum_spanning_tree_prims.py) * [Multi Heuristic Astar](https://github.com/TheAlgorithms/Python/blob/master/graphs/multi_heuristic_astar.py) @@ -575,6 +576,7 @@ * [Ternary Search](https://github.com/TheAlgorithms/Python/blob/master/searches/ternary_search.py) ## Sorts + * [Bead Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/bead_sort.py) * [Bitonic Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/bitonic_sort.py) * [Bogo Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/bogo_sort.py) * [Bubble Sort](https://github.com/TheAlgorithms/Python/blob/master/sorts/bubble_sort.py) From 6c72d3e84f5e7f292d015cf792b35ba5667fc6e2 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 23 May 2020 13:10:18 +0200 Subject: [PATCH 06/14] Update minimum_spanning_tree_boruvka.py --- graphs/minimum_spanning_tree_boruvka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 1ef13b24200e..d4367e5ae46d 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -157,6 +157,7 @@ def boruvka_mst(graph): 3 -> 2 == 3 2 -> 3 == 3 + """ num_components = graph.num_vertices From 8e7d4b8b2d75714370427bee1e61621ae8afb46d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 09:21:52 +0200 Subject: [PATCH 07/14] No blank line in doctest --- graphs/minimum_spanning_tree_boruvka.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index d4367e5ae46d..a608964220d3 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -156,8 +156,6 @@ def boruvka_mst(graph): 0 -> 2 == 2 3 -> 2 == 3 2 -> 3 == 3 - - """ num_components = graph.num_vertices From 87e661c2fa32b2fe9c3df5500c2ca2a7b4b7d039 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 09:29:55 +0200 Subject: [PATCH 08/14] --- graphs/minimum_spanning_tree_boruvka.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index a608964220d3..307c9be4a79c 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -156,6 +156,7 @@ def boruvka_mst(graph): 0 -> 2 == 2 3 -> 2 == 3 2 -> 3 == 3 + """ num_components = graph.num_vertices From c08c697828d17de95aaab8a17deb140ccf05b04e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 09:45:11 +0200 Subject: [PATCH 09/14] Avoid mutable default values https://docs.python-guide.org/writing/gotchas/ --- graphs/minimum_spanning_tree_boruvka.py | 55 +++++++------------------ 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 307c9be4a79c..7f78abd40e6f 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -2,17 +2,14 @@ class Graph: """ Data structure to store graphs (based on adjacency lists) """ - def __init__(self): - self.num_vertices = 0 self.num_edges = 0 self.adjacency = {} def add_vertex(self, vertex): """ - Adds a vertex to the graph - + Add a vertex to the graph """ if vertex not in self.adjacency: self.adjacency[vertex] = {} @@ -20,24 +17,19 @@ def add_vertex(self, vertex): def add_edge(self, head, tail, weight): """ - Adds an edge to the graph - + Add an edge to the graph """ - self.add_vertex(head) self.add_vertex(tail) - if head == tail: return - self.adjacency[head][tail] = weight self.adjacency[tail][head] = weight def distinct_weight(self): """ For Boruvks's algorithm the weights should be distinct - Converts the weights to be distinct - + Convert the weights to be distinct """ edges = self.get_edges() for edge in edges: @@ -45,7 +37,6 @@ def distinct_weight(self): edges.remove((tail, head, weight)) for i in range(len(edges)): edges[i] = list(edges[i]) - edges.sort(key=lambda e: e[2]) for i in range(len(edges) - 1): if edges[i][2] >= edges[i + 1][2]: @@ -57,37 +48,33 @@ def distinct_weight(self): def __str__(self): """ - Returns string representation of the graph + Return a string representation of the graph """ - string = "" - for tail in self.adjacency: - for head in self.adjacency[tail]: - weight = self.adjacency[head][tail] - string += "%d -> %d == %d\n" % (head, tail, weight) - return string + return "\n".join(f"{head} -> {tail} == {self.adjacency[head][tail]}" + for head in self.adjacency[tail] + for tail in self.adjacency) def get_edges(self): """ - Returna all edges in the graph + Return all edges in the graph """ - output = [] - for tail in self.adjacency: - for head in self.adjacency[tail]: - output.append((tail, head, self.adjacency[head][tail])) - return output + return [(tail, head, self.adjacency[head][tail]) + for head in self.adjacency[tail] + for tail in self.adjacency)] def get_vertices(self): """ - Returns all vertices in the graph + Return all vertices in the graph """ return self.adjacency.keys() @staticmethod def build(vertices=[], edges=[]): """ - Builds a graph from the given set of vertices and edges - + Build a graph from the given set of vertices and edges """ + vertices = vertices or [] # Avoid mutable default values + edges = edges or [] g = Graph() for vertex in vertices: g.add_vertex(vertex) @@ -99,7 +86,6 @@ class UnionFind(object): """ Disjoint set Union and Find for Boruvka's algorithm """ - def __init__(self): self.parent = {} self.rank = {} @@ -110,7 +96,6 @@ def __len__(self): def make_set(self, item): if item in self.parent: return self.find(item) - self.parent[item] = item self.rank[item] = 0 return item @@ -125,18 +110,14 @@ def find(self, item): def union(self, item1, item2): root1 = self.find(item1) root2 = self.find(item2) - if root1 == root2: return root1 - if self.rank[root1] > self.rank[root2]: self.parent[root2] = root1 return root1 - if self.rank[root1] < self.rank[root2]: self.parent[root1] = root2 return root2 - if self.rank[root1] == self.rank[root2]: self.rank[root1] += 1 self.parent[root2] = root1 @@ -156,17 +137,14 @@ def boruvka_mst(graph): 0 -> 2 == 2 3 -> 2 == 3 2 -> 3 == 3 - """ num_components = graph.num_vertices - union_find = Graph.UnionFind() mst_edges = [] while num_components > 1: cheap_edge = {} for vertex in graph.get_vertices(): cheap_edge[vertex] = -1 - edges = graph.get_edges() for edge in edges: head, tail, weight = edge @@ -188,5 +166,4 @@ def boruvka_mst(graph): union_find.union(head, tail) mst_edges.append(cheap_edge[vertex]) num_components = num_components - 1 - mst = Graph.build(edges=mst_edges) - return mst + return Graph.build(edges=mst_edges) From 042f2c5052b495ed67a1d57336f51c9ea8106177 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 09:50:06 +0200 Subject: [PATCH 10/14] Update minimum_spanning_tree_boruvka.py --- graphs/minimum_spanning_tree_boruvka.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 7f78abd40e6f..f8047173fa6c 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -60,7 +60,7 @@ def get_edges(self): """ return [(tail, head, self.adjacency[head][tail]) for head in self.adjacency[tail] - for tail in self.adjacency)] + for tail in self.adjacency] def get_vertices(self): """ From 8e55384d3ee44975c72f4bb04a815a813156844c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 09:51:05 +0200 Subject: [PATCH 11/14] Avoid mutable default values --- graphs/minimum_spanning_tree_boruvka.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index f8047173fa6c..c5d5538c8176 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -69,7 +69,7 @@ def get_vertices(self): return self.adjacency.keys() @staticmethod - def build(vertices=[], edges=[]): + def build(vertices=None, edges=None): """ Build a graph from the given set of vertices and edges """ From 2610ada8f118115aeacfeb6b9775f99da4e9a8b4 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 25 May 2020 07:51:29 +0000 Subject: [PATCH 12/14] fixup! Format Python code with psf/black push --- graphs/minimum_spanning_tree_boruvka.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index c5d5538c8176..6864571be88f 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -2,6 +2,7 @@ class Graph: """ Data structure to store graphs (based on adjacency lists) """ + def __init__(self): self.num_vertices = 0 self.num_edges = 0 @@ -50,17 +51,21 @@ def __str__(self): """ Return a string representation of the graph """ - return "\n".join(f"{head} -> {tail} == {self.adjacency[head][tail]}" - for head in self.adjacency[tail] - for tail in self.adjacency) + return "\n".join( + f"{head} -> {tail} == {self.adjacency[head][tail]}" + for head in self.adjacency[tail] + for tail in self.adjacency + ) def get_edges(self): """ Return all edges in the graph """ - return [(tail, head, self.adjacency[head][tail]) - for head in self.adjacency[tail] - for tail in self.adjacency] + return [ + (tail, head, self.adjacency[head][tail]) + for head in self.adjacency[tail] + for tail in self.adjacency + ] def get_vertices(self): """ @@ -86,6 +91,7 @@ class UnionFind(object): """ Disjoint set Union and Find for Boruvka's algorithm """ + def __init__(self): self.parent = {} self.rank = {} From 531665f3c3c70cead2b3f23f43c6ff5ab0d8207c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 25 May 2020 10:17:06 +0200 Subject: [PATCH 13/14] Update minimum_spanning_tree_boruvka.py --- graphs/minimum_spanning_tree_boruvka.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 6864571be88f..26dc75990828 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -51,21 +51,17 @@ def __str__(self): """ Return a string representation of the graph """ - return "\n".join( - f"{head} -> {tail} == {self.adjacency[head][tail]}" - for head in self.adjacency[tail] - for tail in self.adjacency - ) + return "\n".join("{} -> {} == {}".format(*edge) for edge in self.get_edges()) def get_edges(self): """ Return all edges in the graph """ - return [ - (tail, head, self.adjacency[head][tail]) - for head in self.adjacency[tail] - for tail in self.adjacency - ] + output = [] + for tail in self.adjacency: + for head in self.adjacency[tail]: + output.append((tail, head, self.adjacency[head][tail])) + return output def get_vertices(self): """ From 00eea57905a55b648de3ab1fb8701ca02f21e24a Mon Sep 17 00:00:00 2001 From: Nitisha Bharathi <30657775+nitishabharathi@users.noreply.github.com> Date: Mon, 25 May 2020 15:37:38 +0530 Subject: [PATCH 14/14] Update minimum_spanning_tree_boruvka.py --- graphs/minimum_spanning_tree_boruvka.py | 46 +++++++++++++++++++------ 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/graphs/minimum_spanning_tree_boruvka.py b/graphs/minimum_spanning_tree_boruvka.py index 26dc75990828..f65aa7cef031 100644 --- a/graphs/minimum_spanning_tree_boruvka.py +++ b/graphs/minimum_spanning_tree_boruvka.py @@ -4,13 +4,15 @@ class Graph: """ def __init__(self): + self.num_vertices = 0 self.num_edges = 0 self.adjacency = {} def add_vertex(self, vertex): """ - Add a vertex to the graph + Adds a vertex to the graph + """ if vertex not in self.adjacency: self.adjacency[vertex] = {} @@ -18,19 +20,24 @@ def add_vertex(self, vertex): def add_edge(self, head, tail, weight): """ - Add an edge to the graph + Adds an edge to the graph + """ + self.add_vertex(head) self.add_vertex(tail) + if head == tail: return + self.adjacency[head][tail] = weight self.adjacency[tail][head] = weight def distinct_weight(self): """ For Boruvks's algorithm the weights should be distinct - Convert the weights to be distinct + Converts the weights to be distinct + """ edges = self.get_edges() for edge in edges: @@ -38,6 +45,7 @@ def distinct_weight(self): edges.remove((tail, head, weight)) for i in range(len(edges)): edges[i] = list(edges[i]) + edges.sort(key=lambda e: e[2]) for i in range(len(edges) - 1): if edges[i][2] >= edges[i + 1][2]: @@ -49,13 +57,18 @@ def distinct_weight(self): def __str__(self): """ - Return a string representation of the graph + Returns string representation of the graph """ - return "\n".join("{} -> {} == {}".format(*edge) for edge in self.get_edges()) + string = "" + for tail in self.adjacency: + for head in self.adjacency[tail]: + weight = self.adjacency[head][tail] + string += "%d -> %d == %d\n" % (head, tail, weight) + return string.rstrip("\n") def get_edges(self): """ - Return all edges in the graph + Returna all edges in the graph """ output = [] for tail in self.adjacency: @@ -65,18 +78,21 @@ def get_edges(self): def get_vertices(self): """ - Return all vertices in the graph + Returns all vertices in the graph """ return self.adjacency.keys() @staticmethod def build(vertices=None, edges=None): """ - Build a graph from the given set of vertices and edges + Builds a graph from the given set of vertices and edges + """ - vertices = vertices or [] # Avoid mutable default values - edges = edges or [] g = Graph() + if vertices is None: + vertices = [] + if edges is None: + edge = [] for vertex in vertices: g.add_vertex(vertex) for edge in edges: @@ -98,6 +114,7 @@ def __len__(self): def make_set(self, item): if item in self.parent: return self.find(item) + self.parent[item] = item self.rank[item] = 0 return item @@ -112,14 +129,18 @@ def find(self, item): def union(self, item1, item2): root1 = self.find(item1) root2 = self.find(item2) + if root1 == root2: return root1 + if self.rank[root1] > self.rank[root2]: self.parent[root2] = root1 return root1 + if self.rank[root1] < self.rank[root2]: self.parent[root1] = root2 return root2 + if self.rank[root1] == self.rank[root2]: self.rank[root1] += 1 self.parent[root2] = root1 @@ -141,12 +162,14 @@ def boruvka_mst(graph): 2 -> 3 == 3 """ num_components = graph.num_vertices + union_find = Graph.UnionFind() mst_edges = [] while num_components > 1: cheap_edge = {} for vertex in graph.get_vertices(): cheap_edge[vertex] = -1 + edges = graph.get_edges() for edge in edges: head, tail, weight = edge @@ -168,4 +191,5 @@ def boruvka_mst(graph): union_find.union(head, tail) mst_edges.append(cheap_edge[vertex]) num_components = num_components - 1 - return Graph.build(edges=mst_edges) + mst = Graph.build(edges=mst_edges) + return mst