|
1 |
| -import copy |
| 1 | +""" |
| 2 | +Kruskal algorithm for minimum spanning tree in a weighted graph with union–find data structure |
| 3 | +""" |
| 4 | +__author__ = "Michele De Vita <[email protected]>" |
| 5 | +__date__ = "14/07/2017" |
2 | 6 |
|
3 | 7 |
|
4 |
| -def get_nodes(edges_weighted: list): |
| 8 | +def get_vertexes(edges_weighted: list): |
5 | 9 | return set(sum((edge for edge, weight in edges_weighted), ()))
|
6 | 10 |
|
7 | 11 |
|
8 |
| -def is_reversed(curr_edge, edge): |
9 |
| - return curr_edge[0] == edge[1] and curr_edge[1] == edge[0] |
| 12 | +def set_of(vertex, forest): |
| 13 | + for tree in forest: |
| 14 | + if vertex in tree: |
| 15 | + return tree |
| 16 | + return None |
10 | 17 |
|
11 | 18 |
|
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]) |
| 19 | +def union(u_set, v_set, forest): |
| 20 | + forest.remove(u_set) |
| 21 | + forest.remove(v_set) |
| 22 | + forest.append(v_set + u_set) |
| 23 | + return forest |
34 | 24 |
|
35 | 25 |
|
36 | 26 | def minimum_spanning_tree(edges_weighted: list):
|
37 | 27 | """
|
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: |
| 28 | + :param edges_weighted: A list of pair with first element the edge as tuple |
| 29 | + and the weight as second element (e.g. ((1,4), 5) ) |
| 30 | + :return: the list of edges explored |
41 | 31 | """
|
42 | 32 | 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 |
| 33 | + edges_explored = [] |
| 34 | + forest = [[v] for v in get_vertexes(edges_weighted)] |
| 35 | + for (u, v), weight in edges_weighted: |
| 36 | + u_set, v_set = set_of(u, forest), set_of(v, forest) |
| 37 | + if u_set != v_set: |
| 38 | + forest = union(u_set, v_set, forest) |
| 39 | + edges_explored.append(((u, v), weight)) |
| 40 | + return edges_explored |
| 41 | + |
| 42 | + |
| 43 | +def time_complexities(): |
| 44 | + return '''Worst case: O(E log(V)) where E in the number of edges and V the number of vertexes''' |
| 45 | + |
| 46 | + |
| 47 | +def get_code(): |
| 48 | + import inspect |
| 49 | + return inspect.getsource(minimum_spanning_tree) |
0 commit comments