examples: 2 new examples for graph algorithms (topological sorting) (#14303)

Claudio Cesar de Sá 2022-05-05 12:08:08 -03:00 committed by Jef Roosens
parent 4f6b7a384f
commit 3f588a1c4e
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
2 changed files with 236 additions and 0 deletions

View File

@ -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
}

View File

@ -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']
}