v / examples / graphs / dfs.v
103 lines · 94 sloc · 3.21 KB · 2332ecff4811b8c97dfda8e825170e9397962519
Raw
1// Author: CCS
2// I follow literally code in C, done many years ago
3
4fn main() {
5 // Adjacency matrix as a map
6 // Example 01
7 graph_01 := {
8 'A': ['B', 'C']
9 'B': ['A', 'D', 'E']
10 'C': ['A', 'F']
11 'D': ['B']
12 'E': ['F', 'B', 'F']
13 'F': ['C', 'E']
14 }
15 // Example 02
16 graph_02 := {
17 'A': ['B', 'C', 'D']
18 'B': ['E']
19 'C': ['F']
20 'D': ['E']
21 'E': ['H']
22 'F': ['H']
23 'G': ['H']
24 'H': ['E', 'F', 'G']
25 }
26 path_01 := depth_first_search_path(graph_01, 'A', 'F')
27 println('\n Graph_01: a first path from node A to node F is: ${path_01.reverse()}')
28 path_02 := depth_first_search_path(graph_02, 'A', 'H')
29 println('\n Graph_02: a first path from node A to node H is: ${path_02.reverse()}')
30}
31
32// Depth-First Search (BFS) allows you to find a path between two nodes in the graph.
33fn depth_first_search_path(graph map[string][]string, start string, target string) []string {
34 mut path := []string{} // ONE PATH with SUCCESS = array
35 mut stack := []string{} // a stack ... many nodes
36 // all_nodes := graph.keys() // get a key of this map
37 mut visited := visited_init(graph) // a map fully with false in all vertex
38 // false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
39
40 stack << start // first push on the stack
41 for stack.len > 0 {
42 mut node := stack.pop() // get the top node and remove it from the stack
43
44 // check if this node is already visited
45 if visited[node] == false {
46 // if no ... test it and search for a final node
47 visited[node] = true // means: node visited
48 if node == target {
49 path = build_path_reverse(graph, start, node, visited)
50 return path
51 }
52 // Exploring of node removed from stack and add its relatives
53 print('\n Exploring of node ${node} (true/false): ${graph[node]}')
54 // graph[node].reverse() take a classical choice for DFS
55 // at most os left in this case.
56 // use vertex in graph[node] the choice is right
57
58 // take all nodes from the node
59 for vertex in graph[node].reverse() {
60 // println("\n ...${vertex}")
61 // not explored yet
62 if visited[vertex] == false {
63 stack << vertex
64 }
65 }
66 print('\n Stack: ${stack} (only not visited) \n Visited: ${visited}')
67 }
68 }
69 path = ['Path not found, problem in the Graph, start or end nodes! ']
70 return path
71}
72
73// Creating aa map to initialize with of visited nodes .... all with false in the init
74// so these nodes are NOT VISITED YET
75fn visited_init(a_graph map[string][]string) map[string]bool {
76 mut temp := map[string]bool{} // attention in these initializations with maps
77 for i, _ in a_graph {
78 temp[i] = false
79 }
80 return temp
81}
82
83// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
84fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
85 print('\n\n Nodes visited (true) or no (false): ${visited}')
86 array_of_nodes := graph.keys()
87 mut current := final
88 mut path := []string{}
89 path << current
90
91 for current != start {
92 for i in array_of_nodes {
93 if current in graph[i] && visited[i] == true {
94 current = i
95 break // the first occurrence is enough
96 }
97 }
98 path << current // updating the path tracked
99 }
100 return path
101}
102
103//*****************************************************
104