|
| 1 | +// Author: ccs |
| 2 | +// I follow literally code in C, done many years ago |
| 3 | + |
| 4 | +fn 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 | + // println('Graph: $graph') |
| 27 | + path_01 := depth_first_search_path(graph_01, 'A', 'F') |
| 28 | + println('\n Graph_01: a first path from node A to node F is: $path_01.reverse()') |
| 29 | + path_02 := depth_first_search_path(graph_02, 'A', 'H') |
| 30 | + println('\n Graph_02: a first path from node A to node F is: $path_02.reverse()') |
| 31 | +} |
| 32 | + |
| 33 | +// Depth-First Search (BFS) allows you to find a path between two nodes in the graph. |
| 34 | +fn depth_first_search_path(graph map[string][]string, start string, target string) []string { |
| 35 | + mut path := []string{} // ONE PATH with SUCCESS = array |
| 36 | + mut stack := []string{} // a stack ... many nodes |
| 37 | + // all_nodes := graph.keys() // get a key of this map |
| 38 | + n_nodes := graph.len // numbers of nodes of this graph |
| 39 | + mut visited := a_map_nodes_bool(n_nodes) // a map fully |
| 40 | + // false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false} |
| 41 | + |
| 42 | + stack << start // first push on the stack |
| 43 | + for stack.len > 0 { |
| 44 | + mut node := stack.pop() // get the top node and remove it from the stack |
| 45 | + |
| 46 | + // check if this node is already visited |
| 47 | + if visited[node] == false { |
| 48 | + // if no ... test it searchin for a final node |
| 49 | + visited[node] = true // means: node visited |
| 50 | + if node == target { |
| 51 | + path = build_path_reverse(graph, start, node, visited) |
| 52 | + return path |
| 53 | + } |
| 54 | + // Exploring of node removed from stack and add its relatives |
| 55 | + print('\n Exploring of node $node (true/false): ${graph[node]}') |
| 56 | + // graph[node].reverse() take a classical choice for DFS |
| 57 | + // at most os left in this case. |
| 58 | + // use vertex in graph[node] the choice is right |
| 59 | + |
| 60 | + // take all nodes from the node |
| 61 | + for vertex in graph[node].reverse() { |
| 62 | + // println("\n ...${vertex}") |
| 63 | + // not explored yet |
| 64 | + if visited[vertex] == false { |
| 65 | + stack << vertex |
| 66 | + } |
| 67 | + } |
| 68 | + print('\n Stack: $stack (only not visited) \n Visited: $visited') |
| 69 | + } |
| 70 | + } |
| 71 | + path = ['Path not found, problem in the Graph, start or end nodes! '] |
| 72 | + return path |
| 73 | +} |
| 74 | + |
| 75 | +// Creating a map for nodes not VISITED visited ... |
| 76 | +// starting by false ===> means this node was not visited yet |
| 77 | +fn a_map_nodes_bool(size int) map[string]bool { |
| 78 | + mut my_map := map[string]bool{} // look this map ... |
| 79 | + for i in 0 .. size { |
| 80 | + my_map[u8(65 + i).ascii_str()] = false |
| 81 | + } |
| 82 | + return my_map |
| 83 | +} |
| 84 | + |
| 85 | +// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node |
| 86 | +fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string { |
| 87 | + print('\n\n Nodes visited (true) or no (false): $visited') |
| 88 | + array_of_nodes := graph.keys() |
| 89 | + mut current := final |
| 90 | + mut path := []string{} |
| 91 | + path << current |
| 92 | + |
| 93 | + for current != start { |
| 94 | + for i in array_of_nodes { |
| 95 | + if (current in graph[i]) && (visited[i] == true) { |
| 96 | + current = i |
| 97 | + break // the first ocurrence is enough |
| 98 | + } |
| 99 | + } |
| 100 | + path << current // updating the path tracked |
| 101 | + } |
| 102 | + return path |
| 103 | +} |
0 commit comments