Skip to content

Commit a2db44b

Browse files
authored
examples: add 2 more graph search examples (DFS and BFS), move them into examples/graphs (#14131)
1 parent 5dce091 commit a2db44b

File tree

3 files changed

+210
-15
lines changed

3 files changed

+210
-15
lines changed

examples/bfs.v renamed to examples/graphs/bfs.v

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
fn main() {
2+
graph := {
3+
'A': ['B', 'C']
4+
'B': ['A', 'D', 'E']
5+
'C': ['A', 'F']
6+
'D': ['B']
7+
'E': ['B', 'F']
8+
'F': ['C', 'E']
9+
}
10+
println('Graph: $graph')
11+
path := breadth_first_search_path(graph, 'A', 'F')
12+
println('The shortest path from node A to node F is: $path')
13+
assert path == ['A', 'C', 'F']
14+
}
15+
116
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
217
fn breadth_first_search_path(graph map[string][]string, vertex string, target string) []string {
318
mut path := []string{}
@@ -24,18 +39,3 @@ fn breadth_first_search_path(graph map[string][]string, vertex string, target st
2439
}
2540
return path
2641
}
27-
28-
fn main() {
29-
graph := {
30-
'A': ['B', 'C']
31-
'B': ['A', 'D', 'E']
32-
'C': ['A', 'F']
33-
'D': ['B']
34-
'E': ['B', 'F']
35-
'F': ['C', 'E']
36-
}
37-
println('Graph: $graph')
38-
path := breadth_first_search_path(graph, 'A', 'F')
39-
println('The shortest path from node A to node F is: $path')
40-
assert path == ['A', 'C', 'F']
41-
}

examples/graphs/bfs2.v

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Author: ccs
2+
// I follow literally code in C, done many years ago
3+
fn main() {
4+
// Adjacency matrix as a map
5+
graph := {
6+
'A': ['B', 'C']
7+
'B': ['A', 'D', 'E']
8+
'C': ['A', 'F']
9+
'D': ['B']
10+
'E': ['B', 'F']
11+
'F': ['C', 'E']
12+
}
13+
println('Graph: $graph')
14+
path := breadth_first_search_path(graph, 'A', 'F')
15+
println('\n The shortest path from node A to node F is: $path.reverse()')
16+
}
17+
18+
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
19+
fn breadth_first_search_path(graph map[string][]string, start string, target string) []string {
20+
mut path := []string{} // ONE PATH with SUCCESS = array
21+
mut queue := []string{} // a queue ... many paths
22+
// all_nodes := graph.keys() // get a key of this map
23+
n_nodes := graph.len // numbers of nodes of this graph
24+
// a map to store all the nodes visited to avoid cycles
25+
// start all them with False, not visited yet
26+
mut visited := a_map_nodes_bool(n_nodes) // a map fully
27+
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
28+
queue << start // first arrival
29+
for queue.len != 0 {
30+
mut node := departure(mut queue) // get the front node and remove it
31+
if visited[node] == false { // check if this node is already visited
32+
// if no ... test it searchinf for a final node
33+
visited[node] = true // means: visit this node
34+
if node == target {
35+
path = build_path_reverse(graph, start, node, visited)
36+
return path
37+
}
38+
// Expansion of node removed from queue
39+
print('\n Expansion of node $node (true/false): ${graph[node]}')
40+
// take all nodes from the node
41+
for vertex in graph[node] { // println("\n ...${vertex}")
42+
// not explored yet
43+
if visited[vertex] == false {
44+
queue << vertex
45+
}
46+
}
47+
print('\n QUEUE: $queue (only not visited) \n Visited: $visited')
48+
}
49+
}
50+
path = ['Path not found, problem in the Graph, start or end nodes! ']
51+
return path
52+
}
53+
54+
// Creating a map for VISITED nodes ...
55+
// starting by false ===> means this node was not visited yet
56+
fn a_map_nodes_bool(size int) map[string]bool {
57+
mut my_map := map[string]bool{} // look this map ...
58+
base := u8(65)
59+
mut key := base.ascii_str()
60+
for i in 0 .. size {
61+
key = u8(base + i).ascii_str()
62+
my_map[key] = false
63+
}
64+
return my_map
65+
}
66+
67+
// classical removing of a node from the start of a queue
68+
fn departure(mut queue []string) string {
69+
mut x := queue[0]
70+
queue.delete(0)
71+
return x
72+
}
73+
74+
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
75+
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
76+
print('\n\n Nodes visited (true) or no (false): $visited')
77+
array_of_nodes := graph.keys()
78+
mut current := final
79+
mut path := []string{}
80+
path << current
81+
82+
for (current != start) {
83+
for i in array_of_nodes {
84+
if (current in graph[i]) && (visited[i] == true) {
85+
current = i
86+
break // the first ocurrence is enough
87+
}
88+
}
89+
path << current // update the path tracked
90+
}
91+
return path
92+
}

examples/graphs/dfs.v

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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

Comments
 (0)