| 1 | // The idea of this algorithm follow : |
| 2 | // https://www.gatevidyalay.com/topological-sort-topological-sorting/ (GREEDY) |
| 3 | // (no cycles are detected) |
| 4 | // https://en.wikipedia.org/wiki/Topological_sorting ... just the input data |
| 5 | // and the Kahn algorithm |
| 6 | // Author: CCS |
| 7 | |
| 8 | // the idea is rude: https://www.gatevidyalay.com/topological-sort-topological-sorting/ |
| 9 | fn topog_sort_greedy(graph map[string][]string) []string { |
| 10 | n_nodes := graph.len // numbers of nodes of this graph |
| 11 | mut top_order := []string{} // a vector with sequence of nodes visited |
| 12 | mut count := 0 |
| 13 | /* |
| 14 | IDEA ( a greedy algorithm ): |
| 15 | |
| 16 | 1. choose always the node with smallest input degree |
| 17 | 2. visit it |
| 18 | 3. put it in the output vector |
| 19 | 4. remove it from graph |
| 20 | 5. update the graph (a new graph) |
| 21 | 6. find a new vector degree |
| 22 | 7. until all nodes has been visited |
| 23 | Back to step 1 (used the variable count) |
| 24 | |
| 25 | Maybe it seems the Kahn's algorithm |
| 26 | */ |
| 27 | mut v_degree := in_degree(graph) // return: map [string] int |
| 28 | print('V Degree ${v_degree}') |
| 29 | mut small_degree := min_degree(v_degree) |
| 30 | mut new_graph := remove_node_from_graph(small_degree, graph) |
| 31 | top_order << small_degree |
| 32 | count++ |
| 33 | |
| 34 | for (count < n_nodes) { |
| 35 | v_degree = in_degree(new_graph) // return: map [string] int |
| 36 | print('\nV Degree ${v_degree}') |
| 37 | small_degree = min_degree(v_degree) |
| 38 | new_graph = remove_node_from_graph(small_degree, new_graph) |
| 39 | |
| 40 | top_order << small_degree |
| 41 | count++ |
| 42 | } |
| 43 | // print("\n New Graph ${new_graph}") |
| 44 | |
| 45 | return top_order |
| 46 | } |
| 47 | |
| 48 | // Give a node, return a list with all nodes incidents or fathers of this node |
| 49 | fn all_fathers(node string, a_map map[string][]string) []string { |
| 50 | mut array_of_keys := a_map.keys() // get a key of this map |
| 51 | mut all_incident := []string{} |
| 52 | for i in array_of_keys { |
| 53 | // in : function |
| 54 | if node in a_map[i] { |
| 55 | all_incident << i // a queue of this search |
| 56 | } |
| 57 | } |
| 58 | return all_incident |
| 59 | } |
| 60 | |
| 61 | // Input: a map with input degree values, return the key with smallest value |
| 62 | fn min_degree(a_map map[string]int) string { |
| 63 | mut array_of_keys := a_map.keys() // get a key of this map |
| 64 | mut key_min := array_of_keys.first() |
| 65 | mut val_min := a_map[key_min] |
| 66 | // print("\n MIN: ${val_min} \t key_min: ${key_min} \n the map inp_degree: ${a_map}") |
| 67 | for i in array_of_keys { |
| 68 | // there is a smaller |
| 69 | if val_min > a_map[i] { |
| 70 | val_min = a_map[i] |
| 71 | key_min = i |
| 72 | } |
| 73 | } |
| 74 | return key_min // the key with smallest value |
| 75 | } |
| 76 | |
| 77 | // Given a graph ... return a list of integer with degree of each node |
| 78 | fn in_degree(a_map map[string][]string) map[string]int { |
| 79 | mut array_of_keys := a_map.keys() // get a key of this map |
| 80 | // print(array_of_keys) |
| 81 | mut degree := map[string]int{} |
| 82 | for i in array_of_keys { |
| 83 | degree[i] = all_fathers(i, a_map).len |
| 84 | } |
| 85 | // print("\n Degree ${in_degree}" ) |
| 86 | return degree // a vector of the indegree graph |
| 87 | } |
| 88 | |
| 89 | // REMOVE A NODE FROM A GRAPH AND RETURN ANOTHER GRAPH |
| 90 | fn remove_node_from_graph(node string, a_map map[string][]string) map[string][]string { |
| 91 | // mut new_graph := map [string] string {} |
| 92 | mut new_graph := a_map.clone() // copy the graph |
| 93 | new_graph.delete(node) |
| 94 | mut all_nodes := new_graph.keys() // get all nodes of this graph |
| 95 | // FOR THE FUTURE with filter |
| 96 | // for i in all_nodes { |
| 97 | // new_graph[i] = new_graph[i].filter(index(it) != node) |
| 98 | // } |
| 99 | // A HELP FROM V discussion GITHUB - thread |
| 100 | for key in all_nodes { |
| 101 | i := new_graph[key].index(node) |
| 102 | if i >= 0 { |
| 103 | new_graph[key].delete(i) |
| 104 | } |
| 105 | } |
| 106 | // print("\n NEW ${new_graph}" ) |
| 107 | return new_graph |
| 108 | } |
| 109 | |
| 110 | fn main() { |
| 111 | // A map illustration to use in a graph |
| 112 | // adjacency matrix |
| 113 | graph_01 := { |
| 114 | 'A': ['C', 'B'] |
| 115 | 'B': ['D'] |
| 116 | 'C': ['D'] |
| 117 | 'D': [] |
| 118 | } |
| 119 | |
| 120 | graph_02 := { |
| 121 | 'A': ['B', 'C', 'D'] |
| 122 | 'B': ['E'] |
| 123 | 'C': ['F'] |
| 124 | 'D': ['G'] |
| 125 | 'E': ['H'] |
| 126 | 'F': ['H'] |
| 127 | 'G': ['H'] |
| 128 | 'H': [] |
| 129 | } |
| 130 | // from: https://en.wikipedia.org/wiki/Topological_sorting |
| 131 | graph_03 := { |
| 132 | '5': ['11'] |
| 133 | '7': ['11', '8'] |
| 134 | '3': ['8', '10'] |
| 135 | '11': ['2', '9', '10'] |
| 136 | '8': ['9'] |
| 137 | '2': [] |
| 138 | '9': [] |
| 139 | '10': [] |
| 140 | } |
| 141 | |
| 142 | println('\nA Topological Sort of G1: ${topog_sort_greedy(graph_01)}') |
| 143 | println('\nA Topological Sort of G2: ${topog_sort_greedy(graph_02)}') |
| 144 | println('\nA Topological Sort of G3: ${topog_sort_greedy(graph_03)}') |
| 145 | // ['2', '9', '10', '11', '5', '8', '7', '3'] |
| 146 | } |
| 147 | |