Skip to content

Commit 660fb6a

Browse files
author
Michele De Vita
committed
implemented krustal with relative unit test
1 parent 89af9ec commit 660fb6a

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

pygorithm/minimun_spanning_tree/__init__.py

Whitespace-only changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import copy
2+
3+
4+
def get_nodes(edges_weighted: list):
5+
return set(sum((edge for edge, weight in edges_weighted), ()))
6+
7+
8+
def is_reversed(curr_edge, edge):
9+
return curr_edge[0] == edge[1] and curr_edge[1] == edge[0]
10+
11+
12+
def has_cycle(edges_w):
13+
edges_w += [((b, a), weight) for (a, b), weight in edges_w]
14+
for edge, weight in edges_w:
15+
if rec_cycle_detector(edge, edge, copy.deepcopy(edges_w), 1):
16+
return True
17+
return False
18+
19+
20+
def rec_cycle_detector(s_edge, curr_edge, edges_w, step=None):
21+
if step > 2 and curr_edge[1] == s_edge[0]:
22+
return True
23+
neightbours = ((edge, weight) for edge, weight in edges_w if
24+
curr_edge[1] == edge[0] and not is_reversed(curr_edge, edge))
25+
for neightbour in neightbours:
26+
edges_w.remove(neightbour)
27+
if rec_cycle_detector(s_edge, neightbour[0], edges_w, step + 1):
28+
return True
29+
return False
30+
31+
32+
def vertex_of(edge_w: tuple) -> set:
33+
return set(edge_w[0])
34+
35+
36+
def minimum_spanning_tree(edges_weighted: list):
37+
"""
38+
:param edges_weighted: A list of pair with first element the edge as tuple (e.g. (1,4))
39+
and the weight as second element
40+
:return:
41+
"""
42+
edges_weighted.sort(key=lambda pair: pair[1])
43+
edges_list = []
44+
e_vertexes = set()
45+
vertexes = get_nodes(edges_weighted)
46+
while vertexes != e_vertexes:
47+
edge_w = edges_weighted.pop(0)
48+
if (len(edges_list) > 2 and not has_cycle(edges_list + [edge_w])) or len(edges_list) <= 2:
49+
e_vertexes.update(vertex_of(edge_w))
50+
edges_list.append(edge_w)
51+
return edges_list

tests/mst_weighted_graph_tests.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import unittest
2+
3+
from pygorithm.minimun_spanning_tree import kruskal
4+
5+
6+
class KruskalTest(unittest.TestCase):
7+
def test_get_nodes(self):
8+
edge_weighted = [((1, 3), 5), ((2, 4), 10), ((4, 1), 4)]
9+
nodes = kruskal.get_nodes(edge_weighted)
10+
expected = {1, 2, 3, 4}
11+
self.assertEqual(nodes, expected)
12+
13+
def test_has_cycle(self):
14+
edge_weighted = [((1, 3), 5), ((3, 4), 10), ((4, 1), 4)]
15+
self.assertTrue(kruskal.has_cycle(edge_weighted))
16+
17+
def test_has_not_cycle(self):
18+
edge_weighted = [((1, 3), 5), ((2, 4), 10), ((4, 1), 4)]
19+
self.assertFalse(kruskal.has_cycle(edge_weighted))
20+
21+
def test_has_cycle_2(self):
22+
edge_weighted = [((1, 3), 5), ((3, 2), 5), ((3, 4), 10), ((4, 1), 4)]
23+
self.assertTrue(kruskal.has_cycle(edge_weighted))
24+
25+
def test_has_cycle_3(self):
26+
edge_weighted = [((2, 3), 8), ((1, 4), 5), ((3, 5), 5), ((4, 6), 6), ((1, 2), 7), ((2, 5), 7)]
27+
self.assertTrue(kruskal.has_cycle(edge_weighted))
28+
29+
def test_minimum_spanning_tree(self):
30+
"""
31+
test taken from the example at the following link: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
32+
"""
33+
edge_weighted = [((1, 2), 7), ((2, 3), 8), ((1, 4), 5), ((2, 4), 9),
34+
((2, 5), 7), ((3, 5), 5), ((4, 6), 6), ((5, 6), 8),
35+
((5, 7), 9), ((6, 7), 11), ((4, 5), 15)]
36+
expected = [((1, 4), 5), ((3, 5), 5), ((4, 6), 6), ((1, 2), 7), ((2, 5), 7), ((5, 7), 9)]
37+
self.assertEqual(kruskal.minimum_spanning_tree(edge_weighted), expected)

0 commit comments

Comments
 (0)