mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
examples: 2 new examples for graph algorithms (topological sorting) (#14303)
This commit is contained in:
parent
9fde5b067b
commit
634796ae42
90
examples/graphs/topological_sorting_dfs.v
Normal file
90
examples/graphs/topological_sorting_dfs.v
Normal 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
|
||||||
|
}
|
146
examples/graphs/topological_sorting_greedy.v
Normal file
146
examples/graphs/topological_sorting_greedy.v
Normal 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']
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user