Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+161
View File
@@ -0,0 +1,161 @@
/*
A V program for Bellman-Ford's single source
shortest path algorithm.
literally adapted from:
https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
// Adapted from this site... from C++ and Python codes
For Portuguese reference
http://rascunhointeligente.blogspot.com/2010/10/o-algoritmo-de-bellman-ford-um.html
code by CCS
*/
const large = 999999 // almost infinity
// a structure to represent a weighted edge in graph
struct EDGE {
mut:
src int
dest int
weight int
}
// building a map of with all edges etc of a graph, represented from a matrix adjacency
// Input: matrix adjacency --> Output: edges list of src, dest and weight
fn build_map_edges_from_graph[T](g [][]T) map[T]EDGE {
n := g.len // TOTAL OF NODES for this graph -- its dimensions
mut edges_map := map[int]EDGE{} // a graph represented by map of edges
mut edge := 0 // a counter of edges
for i in 0 .. n {
for j in 0 .. n {
// if exist an arc ... include as new edge
if g[i][j] != 0 {
edges_map[edge] = EDGE{i, j, g[i][j]}
edge++
}
}
}
// print('${edges_map}')
return edges_map
}
fn print_sol(dist []int) {
n_vertex := dist.len
print('\n Vertex Distance from Source')
for i in 0 .. n_vertex {
print('\n ${i} --> ${dist[i]}')
}
}
// The main function that finds shortest distances from src
// to all other vertices using Bellman-Ford algorithm. The
// function also detects negative weight cycle
fn bellman_ford[T](graph [][]T, src int) {
mut edges := build_map_edges_from_graph[int](graph)
// this function was done to adapt a graph representation
// by a adjacency matrix, to list of adjacency (using a MAP)
n_edges := edges.len // number of EDGES
// Step 1: Initialize distances from src to all other
// vertices as INFINITE
n_vertex := graph.len // adjc matrix ... n nodes or vertex
mut dist := []int{len: n_vertex, init: large} // dist with -1 instead of INFINITY
// mut path := []int{len: n , init:-1} // previous node of each shortest path
dist[src] = 0
// Step 2: Relax all edges |V| - 1 times. A simple
// shortest path from src to any other vertex can have
// at-most |V| - 1 edges
for _ in 0 .. n_vertex {
for j in 0 .. n_edges {
mut u := edges[j].src
mut v := edges[j].dest
mut weight := edges[j].weight
if dist[u] != large && dist[u] + weight < dist[v] {
dist[v] = dist[u] + weight
}
}
}
// Step 3: check for negative-weight cycles. The above
// step guarantees shortest distances if graph doesn't
// contain negative weight cycle. If we get a shorter
// path, then there is a cycle.
for j in 0 .. n_vertex {
mut u := edges[j].src
mut v := edges[j].dest
mut weight := edges[j].weight
if dist[u] != large && dist[u] + weight < dist[v] {
print('\n Graph contains negative weight cycle')
// If negative cycle is detected, simply
// return or an exit(1)
return
}
}
print_sol(dist)
}
fn main() {
// adjacency matrix = cost or weight
graph_01 := [
[0, -1, 4, 0, 0],
[0, 0, 3, 2, 2],
[0, 0, 0, 0, 0],
[0, 1, 5, 0, 0],
[0, 0, 0, -3, 0],
]
// data from https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
graph_02 := [
[0, 2, 0, 6, 0],
[2, 0, 3, 8, 5],
[0, 3, 0, 0, 7],
[6, 8, 0, 0, 9],
[0, 5, 7, 9, 0],
]
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
/*
The graph:
2 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)-------(4)
9
*/
/*
Let us create following weighted graph
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
10
0--------1
| \ |
6| 5\ |15
| \ |
2--------3
4
*/
graph_03 := [
[0, 10, 6, 5],
[10, 0, 0, 15],
[6, 0, 0, 4],
[5, 15, 4, 0],
]
// To find number of columns
// mut cols := an_array[0].len
mut graph := [][]int{} // the graph: adjacency matrix
// for index, g_value in [graph_01, graph_02, graph_03] {
for index, g_value in [graph_01, graph_02, graph_03] {
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
// always starting by node 0
start_node := 0
println('\n\n Graph ${index + 1} using Bellman-Ford algorithm (source node: ${start_node})')
bellman_ford(graph, start_node)
}
println('\n BYE -- OK')
}
+41
View File
@@ -0,0 +1,41 @@
fn main() {
graph := {
'A': ['B', 'C']
'B': ['A', 'D', 'E']
'C': ['A', 'F']
'D': ['B']
'E': ['B', 'F']
'F': ['C', 'E']
}
println('Graph: ${graph}')
path := breadth_first_search_path(graph, 'A', 'F')
println('The shortest path from node A to node F is: ${path}')
assert path == ['A', 'C', 'F']
}
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
fn breadth_first_search_path(graph map[string][]string, vertex string, target string) []string {
mut path := []string{}
mut visited := []string{len: 6, init: vertex}
mut queue := [][][]string{}
queue << [[vertex], path]
for queue.len > 0 {
mut idx := queue.len - 1
node := queue[idx][0][0]
path = queue[idx][1]
queue.delete(idx)
if node == target {
path << node
return path
}
for child in graph[node] {
mut tmp := path.clone()
if child !in visited {
visited << child
tmp << node
queue << [[child], tmp]
}
}
}
return path
}
+90
View File
@@ -0,0 +1,90 @@
// Author: CCS
// I follow literally code in C, done many years ago
fn main() {
// Adjacency matrix as a map
graph := {
'A': ['B', 'C']
'B': ['A', 'D', 'E']
'C': ['A', 'F']
'D': ['B']
'E': ['B', 'F']
'F': ['C', 'E']
}
println('Graph: ${graph}')
path := breadth_first_search_path(graph, 'A', 'F')
println('\n The shortest path from node A to node F is: ${path.reverse()}')
}
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
fn breadth_first_search_path(graph map[string][]string, start string, target string) []string {
mut path := []string{} // ONE PATH with SUCCESS = array
mut queue := []string{} // a queue ... many paths
// all_nodes := graph.keys() // get a key of this map
// a map to store all the nodes visited to avoid cycles
// start all them with False, not visited yet
mut visited := visited_init(graph) // a map fully
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
queue << start // first arrival
for queue.len != 0 {
mut node := departure(mut queue) // get the front node and remove it
if visited[node] == false { // check if this node is already visited
// if no ... test it searchinf for a final node
visited[node] = true // means: visit this node
if node == target {
path = build_path_reverse(graph, start, node, visited)
return path
}
// Expansion of node removed from queue
print('\n Expansion of node ${node} (true/false): ${graph[node]}')
// take all nodes from the node
for vertex in graph[node] { // println("\n ...${vertex}")
// not explored yet
if visited[vertex] == false {
queue << vertex
}
}
print('\n QUEUE: ${queue} (only not visited) \n Visited: ${visited}')
}
}
path = ['Path not found, problem in the Graph, start or end nodes! ']
return path
}
// classical removing of a node from the start of a queue
fn departure(mut queue []string) string {
mut x := queue[0]
queue.delete(0)
return x
}
// 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 temp := map[string]bool{} // attention in these initializations with maps
for i, _ in a_graph {
temp[i] = false
}
return temp
}
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
print('\n\n Nodes visited (true) or no (false): ${visited}')
array_of_nodes := graph.keys()
mut current := final
mut path := []string{}
path << current
for (current != start) {
for i in array_of_nodes {
if current in graph[i] && visited[i] == true {
current = i
break // the first occurrence is enough
}
}
path << current // update the path tracked
}
return path
}
//======================================================
+57
View File
@@ -0,0 +1,57 @@
// Author: CCS & KeitoTobi1
// Backtracking Supported.
import datatypes
fn find_pattern(adj map[string][]string, start string, target string) [][]string {
mut visited := visited_init(adj)
mut queue := datatypes.Queue[[]string]{}
mut res := [][]string{}
queue.push([start])
for !queue.is_empty() {
mut v := queue.pop() or { panic(err) }
node := v.last()
if node == target {
res << v
}
print('Expansion of node ${node} (true/false): ${adj[node]}')
for next in adj[node] {
if visited[next] == false {
mut copy := v.clone()
copy << next
queue.push(copy)
visited[node] = true
}
}
print('Expansion of node ${queue} (true/false): ${visited}\n')
}
return res
}
fn print_pattern(pat [][]string) {
for p in pat {
println(p)
}
}
fn visited_init(adj map[string][]string) map[string]bool {
mut temp := map[string]bool{}
for i, _ in adj {
temp[i] = false
}
return temp
}
fn main() {
adj := {
'A': ['B', 'C']
'B': ['A', 'D', 'E']
'C': ['A', 'F']
'D': ['B']
'E': ['B', 'F']
'F': ['C', 'E']
}
path := find_pattern(adj, 'A', 'F')
println('The all pattern path from node A to node F is:')
print_pattern(path)
}
+103
View File
@@ -0,0 +1,103 @@
// Author: CCS
// I follow literally code in C, done many years ago
fn main() {
// Adjacency matrix as a map
// Example 01
graph_01 := {
'A': ['B', 'C']
'B': ['A', 'D', 'E']
'C': ['A', 'F']
'D': ['B']
'E': ['F', 'B', 'F']
'F': ['C', 'E']
}
// Example 02
graph_02 := {
'A': ['B', 'C', 'D']
'B': ['E']
'C': ['F']
'D': ['E']
'E': ['H']
'F': ['H']
'G': ['H']
'H': ['E', 'F', 'G']
}
path_01 := depth_first_search_path(graph_01, 'A', 'F')
println('\n Graph_01: a first path from node A to node F is: ${path_01.reverse()}')
path_02 := depth_first_search_path(graph_02, 'A', 'H')
println('\n Graph_02: a first path from node A to node H is: ${path_02.reverse()}')
}
// Depth-First Search (BFS) allows you to find a path between two nodes in the graph.
fn depth_first_search_path(graph map[string][]string, start string, target string) []string {
mut path := []string{} // ONE PATH with SUCCESS = array
mut stack := []string{} // a stack ... many nodes
// all_nodes := graph.keys() // get a key of this map
mut visited := visited_init(graph) // a map fully with false in all vertex
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
stack << start // first push on the stack
for stack.len > 0 {
mut node := stack.pop() // get the top node and remove it from the stack
// check if this node is already visited
if visited[node] == false {
// if no ... test it and search for a final node
visited[node] = true // means: node visited
if node == target {
path = build_path_reverse(graph, start, node, visited)
return path
}
// Exploring of node removed from stack and add its relatives
print('\n Exploring of node ${node} (true/false): ${graph[node]}')
// graph[node].reverse() take a classical choice for DFS
// at most os left in this case.
// use vertex in graph[node] the choice is right
// take all nodes from the node
for vertex in graph[node].reverse() {
// println("\n ...${vertex}")
// not explored yet
if visited[vertex] == false {
stack << vertex
}
}
print('\n Stack: ${stack} (only not visited) \n Visited: ${visited}')
}
}
path = ['Path not found, problem in the Graph, start or end nodes! ']
return path
}
// 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 temp := map[string]bool{} // attention in these initializations with maps
for i, _ in a_graph {
temp[i] = false
}
return temp
}
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
print('\n\n Nodes visited (true) or no (false): ${visited}')
array_of_nodes := graph.keys()
mut current := final
mut path := []string{}
path << current
for current != start {
for i in array_of_nodes {
if current in graph[i] && visited[i] == true {
current = i
break // the first occurrence is enough
}
}
path << current // updating the path tracked
}
return path
}
//*****************************************************
+83
View File
@@ -0,0 +1,83 @@
// Author: CCS & KeitoTobi1
// Backtracking Supported.
fn main() {
// Adjacency matrix as a map
// Example 01
graph_01 := {
'A': ['B', 'C']
'B': ['A', 'D', 'E']
'C': ['A', 'F']
'D': ['B']
'E': ['F', 'B', 'F']
'F': ['C', 'E']
}
// Example 02
graph_02 := {
'A': ['B', 'C', 'D']
'B': ['E']
'C': ['F']
'D': ['E']
'E': ['H']
'F': ['H']
'G': ['H']
'H': ['E', 'F', 'G']
}
path_01 := depth_first_search_path(graph_01, 'A', 'F')
println('\n Graph_01: all path pattern from node A to node F is:')
print_pattern(path_01)
path_02 := depth_first_search_path(graph_02, 'A', 'H')
println('\n Graph_02: all path pattern from node A to node F is:')
print_pattern(path_02)
}
fn depth_first_search_path(adj map[string][]string, start string, target string) [][]string {
mut sol := Solution{}
mut path := []string{}
mut visited := visited_init(adj)
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
sol.find_pattern(adj, mut visited, start, target, mut path)
return sol.pattern
}
struct Solution {
pub mut:
pattern [][]string
}
fn (mut s Solution) find_pattern(adj map[string][]string, mut visited map[string]bool, node string, target string,
mut path []string) {
path << node
visited[node] = true
if node == target {
print('\n Founded pattern: ${path}')
s.pattern << [path]
}
print('\n Exploring of node ${node} (true/false): ${adj[node]}')
for i, _ in adj[node] {
if !visited[adj[node][i]] {
mut temp := path.clone()
s.find_pattern(adj, mut visited, adj[node][i], target, mut temp)
}
}
visited[node] = false
print('\n Current: ${node} (only not visited) \n Visited: ${visited}')
}
fn print_pattern(pat [][]string) {
for p in pat {
println(p)
}
}
// 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(adj map[string][]string) map[string]bool {
mut temp := map[string]bool{}
for i, _ in adj {
temp[i] = false
}
return temp
}
+239
View File
@@ -0,0 +1,239 @@
/*
Exploring Dijkstra,
The data example is from
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
by CCS
Dijkstra's single source shortest path algorithm.
The program uses an adjacency matrix representation of a graph
This Dijkstra algorithm uses a priority queue to save
the shortest paths. The queue structure has a data
which is the number of the node,
and the priority field which is the shortest distance.
PS: all the pre-requisites of Dijkstra are considered
$ v run file_name.v
// Creating a executable
$ v run file_name.v -o an_executable.EXE
$ ./an_executable.EXE
Code based from : Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles, Fifth Edition (English Edition)
pseudo code written in C
This idea is quite different: it uses a priority queue to store the current
shortest path evaluated
The priority queue structure built using a list to simulate
the queue. A heap is not used in this case.
*/
// a structure
struct NODE {
mut:
data int // NUMBER OF NODE
priority int // Lower values priority indicate ==> higher priority
}
// Function to push according to priority ... the lower priority is goes ahead
// The "push" always sorted in pq
fn push_pq[T](mut prior_queue []T, data int, priority int) {
mut temp := []T{}
pq_len := prior_queue.len
mut i := 0
for i < pq_len && priority > prior_queue[i].priority {
temp << prior_queue[i]
i++
}
// INSERTING SORTED in the queue
temp << NODE{data, priority} // do the copy in the right place
// copy the another part (tail) of original prior_queue
for i < pq_len {
temp << prior_queue[i]
i++
}
prior_queue = temp.clone() // I am not sure if it the right way
// IS IT THE RIGHT WAY?
}
// Change the priority of a value/node ... exist a value, change its priority
fn updating_priority[T](mut prior_queue []T, search_data int, new_priority int) {
mut i := 0
mut pq_len := prior_queue.len
for i < pq_len {
if search_data == prior_queue[i].data {
prior_queue[i] = NODE{search_data, new_priority} // do the copy in the right place
break
}
i++
// all the list was examined
if i >= pq_len {
print('\n This data ${search_data} does exist ... PRIORITY QUEUE problem\n')
exit(1) // panic(s string)
}
} // end for
}
// a single departure or remove from queue
fn departure_priority[T](mut prior_queue []T) int {
mut x := prior_queue[0].data
prior_queue.delete(0) // or .delete_many(0, 1 )
return x
}
// give a NODE v, return a list with all adjacents
// Take care, only positive EDGES
fn all_adjacents[T](g [][]T, v int) []int {
mut temp := []int{}
for i in 0 .. (g.len) {
if g[v][i] > 0 {
temp << i
}
}
return temp
}
// print the costs from origin up to all nodes
fn print_solution[T](dist []T) {
print('Vertex \tDistance from Source')
for node in 0 .. (dist.len) {
print('\n ${node} ==> \t ${dist[node]}')
}
}
// print all paths and their cost or weight
fn print_paths_dist[T](path []T, dist []T) {
print('\n Read the nodes from right to left (a path): \n')
for node in 1 .. (path.len) {
print('\n ${node} ')
mut i := node
for path[i] != -1 {
print(' <= ${path[i]} ')
i = path[i]
}
print('\t PATH COST: ${dist[node]}')
}
}
// check structure from: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
// s: source for all nodes
// Two results are obtained ... cost and paths
fn dijkstra(g [][]int, s int) {
mut pq_queue := []NODE{} // creating a priority queue
push_pq(mut pq_queue, s, 0) // goes s with priority 0
mut n := g.len
mut dist := []int{len: n, init: -1} // dist with -1 instead of INFINITE
mut path := []int{len: n, init: -1} // previous node of each shortest path
// Distance of source vertex from itself is always 0
dist[s] = 0
for pq_queue.len != 0 {
mut v := departure_priority(mut pq_queue)
// for all W adjacents vertices of v
mut adjs_of_v := all_adjacents(g, v) // all_ADJ of v ....
// print('\n ADJ ${v} is ${adjs_of_v}')
mut new_dist := 0
for w in adjs_of_v {
new_dist = dist[v] + g[v][w]
if dist[w] == -1 {
dist[w] = new_dist
push_pq(mut pq_queue, w, dist[w])
path[w] = v // collecting the previous node -- lowest weight
}
if dist[w] > new_dist {
dist[w] = new_dist
updating_priority(mut pq_queue, w, dist[w])
path[w] = v
}
}
}
// print the constructed distance array
print_solution(dist)
// print('\n \n Previous node of shortest path: ${path}')
print_paths_dist(path, dist)
}
/*
Solution Expected
Vertex Distance from Source
0 0
1 4
2 12
3 19
4 21
5 11
6 9
7 8
8 14
*/
fn main() {
// adjacency matrix = cost or weight
graph_01 := [
[0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0],
]
graph_02 := [
[0, 2, 0, 6, 0],
[2, 0, 3, 8, 5],
[0, 3, 0, 0, 7],
[6, 8, 0, 0, 9],
[0, 5, 7, 9, 0],
]
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
/*
The graph:
2 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)-------(4)
9
*/
/*
Let us create following weighted graph
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
10
0--------1
| \ |
6| 5\ |15
| \ |
2--------3
4
*/
graph_03 := [
[0, 10, 6, 5],
[10, 0, 0, 15],
[6, 0, 0, 4],
[5, 15, 4, 0],
]
// To find number of columns
// mut cols := an_array[0].len
mut graph := [][]int{} // the graph: adjacency matrix
// for index, g_value in [graph_01, graph_02, graph_03] {
for index, g_value in [graph_01, graph_02, graph_03] {
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
// always starting by node 0
start_node := 0
println('\n\n Graph ${index + 1} using Dijkstra algorithm (source node: ${start_node})')
dijkstra(graph, start_node)
}
println('\n BYE -- OK')
}
@@ -0,0 +1,224 @@
/*
Exploring PRIMS,
The data example is from
https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
by CCS
PS: all the pre-requisites of Dijkstra are considered
$ v run file_name.v
Creating a executable
$ v -o an_executable.EXE run file_name.v
$ ./an_executable.EXE
Code based from : Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles, Fifth Edition (English Edition)
pseudo code written in C
This idea is quite different: it uses a priority queue to store the current
shortest path evaluated
The priority queue structure built using a list to simulate
the queue. A heap is not used in this case.
*/
// a structure
struct NODE {
mut:
data int // number of nodes
priority int // Lower values priority indicate ==> higher priority
}
// Function to push according to priority ... the lower priority is goes ahead
// The "push" always sorted in pq
fn push_pq[T](mut prior_queue []T, data int, priority int) {
mut temp := []T{}
pg_len := prior_queue.len
mut i := 0
for i < pg_len && priority > prior_queue[i].priority {
temp << prior_queue[i]
i++
}
// INSERTING SORTED in the queue
temp << NODE{data, priority} // do the copy in the right place
// copy the another part (tail) of original prior_queue
for i < pg_len {
temp << prior_queue[i]
i++
}
prior_queue = temp.clone() // I am not sure if it the right way
}
// Change the priority of a value/node ... exist a value, change its priority
fn updating_priority[T](mut prior_queue []T, search_data int, new_priority int) {
mut i := 0
mut pg_len := prior_queue.len
for i < pg_len {
if search_data == prior_queue[i].data {
prior_queue[i] = NODE{search_data, new_priority} // do the copy in the right place
break
}
i++
// all the list was examined
if i >= pg_len {
// print('\n Priority Queue: ${prior_queue}')
// print('\n These data ${search_data} and ${new_priority} do not exist ... PRIORITY QUEUE problem\n')
// if it does not find ... then push it
push_pq(mut prior_queue, search_data, new_priority)
// exit(1) // panic(s string)
}
} // end for
}
// a single departure or remove from queue
fn departure_priority[T](mut prior_queue []T) int {
mut x := prior_queue[0].data
prior_queue.delete(0) // or .delete_many(0, 1 )
return x
}
// give a NODE v, return a list with all adjacents
// Take care, only positive EDGES
fn all_adjacents[T](g [][]T, v int) []int {
mut temp := []int{}
for i in 0 .. (g.len) {
if g[v][i] > 0 {
temp << i
}
}
return temp
}
// print the costs from origin up to all nodes
// A utility function to print the
// constructed MST stored in parent[]
// print all paths and their cost or weight
fn print_solution(path []int, g [][]int) {
// print(' PATH: ${path} ==> ${path.len}')
print(' Edge \tWeight\n')
mut sum := 0
for node in 0 .. (path.len) {
if path[node] == -1 {
print('\n ${node} <== reference or start node')
} else {
print('\n ${node} <--> ${path[node]} \t${g[node][path[node]]}')
sum += g[node][path[node]]
}
}
print('\n Minimum Cost Spanning Tree: ${sum}\n\n')
}
// check structure from: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
// s: source for all nodes
// Two results are obtained ... cost and paths
fn prim_mst(g [][]int, s int) {
mut pq_queue := []NODE{} // creating a priority queue
push_pq(mut pq_queue, s, 0) // goes s with priority 0
mut n := g.len
mut dist := []int{len: n, init: -1} // dist with -1 instead of INFINITE
mut path := []int{len: n, init: -1} // previous node of each shortest path
// Distance of source vertex from itself is always 0
dist[s] = 0
for pq_queue.len != 0 {
mut v := departure_priority(mut pq_queue)
// for all W adjacents vertices of v
mut adjs_of_v := all_adjacents(g, v) // all_ADJ of v ....
// print('\n :${dist} :: ${pq_queue}')
// print('\n ADJ ${v} is ${adjs_of_v}')
mut new_dist := 0
for w in adjs_of_v {
new_dist = dist[v] + g[v][w]
if dist[w] == -1 {
dist[w] = g[v][w]
push_pq(mut pq_queue, w, dist[w])
path[w] = v // collecting the previous node -- lowest weight
}
if dist[w] > new_dist {
dist[w] = g[v][w] // new_dist//
updating_priority(mut pq_queue, w, dist[w])
path[w] = v // father / previous node
}
}
}
// print('\n \n Previous node of shortest path: ${path}')
// print_paths_dist(path , dist)
print_solution(path, g)
}
/*
Solution Expected graph_02
Edge Weight
0 - 1 2
1 - 2 3
0 - 3 6
1 - 4 5
*/
fn main() {
// adjacency matrix = cost or weight
graph_01 := [
[0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0],
]
graph_02 := [
[0, 2, 0, 6, 0],
[2, 0, 3, 8, 5],
[0, 3, 0, 0, 7],
[6, 8, 0, 0, 9],
[0, 5, 7, 9, 0],
]
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
/*
The graph:
2 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)-------(4)
9
Let us create following weighted graph
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
10
0--------1
| \ |
6| 5\ |15
| \ |
2--------3
4
*/
graph_03 := [
[0, 10, 6, 5],
[10, 0, 0, 15],
[6, 0, 0, 4],
[5, 15, 4, 0],
]
// To find number of columns
// mut cols := an_array[0].len
mut graph := [][]int{} // the graph: adjacency matrix
// for index, g_value in [graph_01, graph_02, graph_03] {
for index, g_value in [graph_01, graph_02, graph_03] {
println('\n Minimal Spanning Tree of graph ${index + 1} using PRIM algorithm')
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
// starting by node x ... see the graphs dimensions
start_node := 0
prim_mst(graph, start_node)
}
println('\n BYE -- OK')
}
@@ -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
}
@@ -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 algorithm ):
1. choose always 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']
}