diff --git a/examples/graphs/topological_sorting_dfs.v b/examples/graphs/topological_sorting_dfs.v new file mode 100644 index 0000000000..659e483815 --- /dev/null +++ b/examples/graphs/topological_sorting_dfs.v @@ -0,0 +1,90 @@ +// https://en.wikipedia.org/wiki/Topological_sorting +// A DFS RECURSIVE ALGORITHM .... +// An alternative algorithm for topological sorting is based on depth-first search. The algorithm loops through each node of the graph, in an arbitrary order, initiating a depth-first search that terminates when it hits any node that has already been visited since the beginning +// of the topological sort or the node has no outgoing edges (i.e. a leaf node) +// Discussion: https://www.gatevidyalay.com/topological-sort-topological-sorting/ +// $ v run dfs_topological_ordering.v +// Author: CCS + +// THE DFS RECURSIVE .... classical searchig for leaves nodes +// the arguments are used in the function to avoid global variables.... +fn dfs_recursive(u string, mut visited map[string]bool, graph map[string][]string, mut top_sorting []string) { + print(' Visiting: $u -> ') + visited[u] = true + + for v in graph[u] { + if visited[v] == false { + dfs_recursive(v, mut visited, graph, mut top_sorting) + } + } + top_sorting << u +} + +// Creating aa map to initialize with of visited nodes .... all with false in the init +// so these nodes are NOT VISITED YET +fn visited_init(a_graph map[string][]string) map[string]bool { + mut array_of_keys := a_graph.keys() // get all keys of this map + mut temp := map[string]bool{} // attention in these initializations with maps + for i in array_of_keys { + temp[i] = false + } + return temp +} + +// attention here a map STRING ---> ONE BOOLEAN ... not a string + +fn main() { + // A map illustration to use in a graph + // the graph: adjacency matrix + graph_01 := { + 'A': ['C', 'B'] + 'B': ['D'] + 'C': ['D'] + 'D': [] + } + + graph_02 := { + 'A': ['B', 'C', 'D'] + 'B': ['E'] + 'C': ['F'] + 'D': ['G'] + 'E': ['H'] + 'F': ['H'] + 'G': ['H'] + 'H': [] // no cycles + } + // from: https://en.wikipedia.org/wiki/Topological_sorting + graph_03 := { + '5': ['11'] + '7': ['11', '8'] + '3': ['8', '10'] + '11': ['2', '9', '10'] + '8': ['9'] + '2': [] + '9': [] + '10': [] + } + + mut graph := map[string][]string{} // the graph: adjacency matrix + for index, g_value in [graph_01, graph_02, graph_03] { + println('Topological sorting for the graph $index using a DFS recursive') + graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE + + // mut n_nodes := graph.len + mut visited := visited_init(graph) // a map with nodes not visited + + // mut start := (graph.keys()).first() // arbitrary, any node if you wish + mut top_sorting := []string{} + // advantages of map ... getting all nodes + for i in graph.keys() { + if visited[i] != true { + dfs_recursive(i, mut visited, graph, mut top_sorting) + } + } + + print('\n A topological sorting of graph $index : ') + // println(g_value) + println(top_sorting.reverse()) + println('') + } // End of for +} diff --git a/examples/graphs/topological_sorting_greedy.v b/examples/graphs/topological_sorting_greedy.v new file mode 100644 index 0000000000..868ec30e33 --- /dev/null +++ b/examples/graphs/topological_sorting_greedy.v @@ -0,0 +1,146 @@ +// The idea of this algorithm follow : +// https://www.gatevidyalay.com/topological-sort-topological-sorting/ (GREEDY) +// (no cycles are detected) +// https://en.wikipedia.org/wiki/Topological_sorting ... just the input data +// and the Kahn algorithm +// Author: CCS + +// the idea is rude: https://www.gatevidyalay.com/topological-sort-topological-sorting/ +fn topog_sort_greedy(graph map[string][]string) []string { + n_nodes := graph.len // numbers of nodes of this graph + mut top_order := []string{} // a vector with sequence of nodes visited + mut count := 0 + /* + IDEA ( a greedy algorythm ): + + 1. choose allways the node with smallest input degree + 2. visit it + 3. put it in the output vector + 4. remove it from graph + 5. update the graph (a new graph) + 6. find a new vector degree + 7. until all nodes has been visited + Back to step 1 (used the variable count) + + Maybe it seems the Kahn's algorithm + */ + mut v_degree := in_degree(graph) // return: map [string] int + print('V Degree $v_degree') + mut small_degree := min_degree(v_degree) + mut new_graph := remove_node_from_graph(small_degree, graph) + top_order << small_degree + count++ + + for (count < n_nodes) { + v_degree = in_degree(new_graph) // return: map [string] int + print('\nV Degree $v_degree') + small_degree = min_degree(v_degree) + new_graph = remove_node_from_graph(small_degree, new_graph) + + top_order << small_degree + count++ + } + // print("\n New Graph ${new_graph}") + + return top_order +} + +// Give a node, return a list with all nodes incidents or fathers of this node +fn all_fathers(node string, a_map map[string][]string) []string { + mut array_of_keys := a_map.keys() // get a key of this map + mut all_incident := []string{} + for i in array_of_keys { + // in : function + if node in a_map[i] { + all_incident << i // a queue of this search + } + } + return all_incident +} + +// Input: a map with input degree values, return the key with smallest value +fn min_degree(a_map map[string]int) string { + mut array_of_keys := a_map.keys() // get a key of this map + mut key_min := array_of_keys.first() + mut val_min := a_map[key_min] + // print("\n MIN: ${val_min} \t key_min: ${key_min} \n the map inp_degree: ${a_map}") + for i in array_of_keys { + // there is a smaller + if val_min > a_map[i] { + val_min = a_map[i] + key_min = i + } + } + return key_min // the key with smallest value +} + +// Given a graph ... return a list of integer with degree of each node +fn in_degree(a_map map[string][]string) map[string]int { + mut array_of_keys := a_map.keys() // get a key of this map + // print(array_of_keys) + mut degree := map[string]int{} + for i in array_of_keys { + degree[i] = all_fathers(i, a_map).len + } + // print("\n Degree ${in_degree}" ) + return degree // a vector of the indegree graph +} + +// REMOVE A NODE FROM A GRAPH AND RETURN ANOTHER GRAPH +fn remove_node_from_graph(node string, a_map map[string][]string) map[string][]string { + // mut new_graph := map [string] string {} + mut new_graph := a_map.clone() // copy the graph + new_graph.delete(node) + mut all_nodes := new_graph.keys() // get all nodes of this graph + // FOR THE FUTURE with filter + // for i in all_nodes { + // new_graph[i] = new_graph[i].filter(index(it) != node) + // } + // A HELP FROM V discussion GITHUB - thread + for key in all_nodes { + i := new_graph[key].index(node) + if i >= 0 { + new_graph[key].delete(i) + } + } + // print("\n NEW ${new_graph}" ) + return new_graph +} + +fn main() { + // A map illustration to use in a graph + // adjacency matrix + graph_01 := { + 'A': ['C', 'B'] + 'B': ['D'] + 'C': ['D'] + 'D': [] + } + + graph_02 := { + 'A': ['B', 'C', 'D'] + 'B': ['E'] + 'C': ['F'] + 'D': ['G'] + 'E': ['H'] + 'F': ['H'] + 'G': ['H'] + 'H': [] + } + // from: https://en.wikipedia.org/wiki/Topological_sorting + graph_03 := { + '5': ['11'] + '7': ['11', '8'] + '3': ['8', '10'] + '11': ['2', '9', '10'] + '8': ['9'] + '2': [] + '9': [] + '10': [] + } + + println('\nA Topological Sort of G1: ${topog_sort_greedy(graph_01)}') + println('\nA Topological Sort of G2: ${topog_sort_greedy(graph_02)}') + println('\nA Topological Sort of G3: ${topog_sort_greedy(graph_03)}') + // ['2', '9', '10', '11', '5', '8', '7', '3'] +}