examples: some new graphs algorithms and improving 2 others (#14556)
parent
e201665e92
commit
5bf246fce6
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
A V program for Bellman-Ford's single source
|
||||||
|
shortest path algorithm.
|
||||||
|
literaly adapted from:
|
||||||
|
https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
|
||||||
|
// Adapted from this site... from C++ and Python codes
|
||||||
|
|
||||||
|
For Portugese reference
|
||||||
|
http://rascunhointeligente.blogspot.com/2010/10/o-algoritmo-de-bellman-ford-um.html
|
||||||
|
|
||||||
|
By CCS
|
||||||
|
*/
|
||||||
|
|
||||||
|
const large = 999999 // almost inifinity
|
||||||
|
|
||||||
|
// 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 dimmension
|
||||||
|
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(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 INIFINITY
|
||||||
|
// mut path := []int{len: n , init:-1} // previous node of each shortest paht
|
||||||
|
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 coluns
|
||||||
|
// 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
|
||||||
|
// allways 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')
|
||||||
|
}
|
||||||
|
|
||||||
|
//=================================================
|
|
@ -1,4 +1,4 @@
|
||||||
// Author: ccs
|
// Author: CCS
|
||||||
// I follow literally code in C, done many years ago
|
// I follow literally code in C, done many years ago
|
||||||
fn main() {
|
fn main() {
|
||||||
// Adjacency matrix as a map
|
// Adjacency matrix as a map
|
||||||
|
@ -20,10 +20,9 @@ fn breadth_first_search_path(graph map[string][]string, start string, target str
|
||||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||||
mut queue := []string{} // a queue ... many paths
|
mut queue := []string{} // a queue ... many paths
|
||||||
// all_nodes := graph.keys() // get a key of this map
|
// all_nodes := graph.keys() // get a key of this map
|
||||||
n_nodes := graph.len // numbers of nodes of this graph
|
|
||||||
// a map to store all the nodes visited to avoid cycles
|
// a map to store all the nodes visited to avoid cycles
|
||||||
// start all them with False, not visited yet
|
// start all them with False, not visited yet
|
||||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
mut visited := visited_init(graph) // a map fully
|
||||||
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||||
queue << start // first arrival
|
queue << start // first arrival
|
||||||
for queue.len != 0 {
|
for queue.len != 0 {
|
||||||
|
@ -51,19 +50,6 @@ fn breadth_first_search_path(graph map[string][]string, start string, target str
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a map for VISITED nodes ...
|
|
||||||
// starting by false ===> means this node was not visited yet
|
|
||||||
fn a_map_nodes_bool(size int) map[string]bool {
|
|
||||||
mut my_map := map[string]bool{} // look this map ...
|
|
||||||
base := u8(65)
|
|
||||||
mut key := base.ascii_str()
|
|
||||||
for i in 0 .. size {
|
|
||||||
key = u8(base + i).ascii_str()
|
|
||||||
my_map[key] = false
|
|
||||||
}
|
|
||||||
return my_map
|
|
||||||
}
|
|
||||||
|
|
||||||
// classical removing of a node from the start of a queue
|
// classical removing of a node from the start of a queue
|
||||||
fn departure(mut queue []string) string {
|
fn departure(mut queue []string) string {
|
||||||
mut x := queue[0]
|
mut x := queue[0]
|
||||||
|
@ -71,6 +57,17 @@ fn departure(mut queue []string) string {
|
||||||
return x
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
|
// 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 {
|
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')
|
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||||
|
@ -90,3 +87,5 @@ fn build_path_reverse(graph map[string][]string, start string, final string, vis
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//======================================================
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Author: ccs
|
// Author: CCS
|
||||||
// I follow literally code in C, done many years ago
|
// I follow literally code in C, done many years ago
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -35,8 +35,7 @@ fn depth_first_search_path(graph map[string][]string, start string, target strin
|
||||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||||
mut stack := []string{} // a stack ... many nodes
|
mut stack := []string{} // a stack ... many nodes
|
||||||
// all_nodes := graph.keys() // get a key of this map
|
// all_nodes := graph.keys() // get a key of this map
|
||||||
n_nodes := graph.len // numbers of nodes of this graph
|
mut visited := visited_init(graph) // a map fully with false in all vertex
|
||||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
|
||||||
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||||
|
|
||||||
stack << start // first push on the stack
|
stack << start // first push on the stack
|
||||||
|
@ -72,14 +71,15 @@ fn depth_first_search_path(graph map[string][]string, start string, target strin
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a map for nodes not VISITED visited ...
|
// Creating aa map to initialize with of visited nodes .... all with false in the init
|
||||||
// starting by false ===> means this node was not visited yet
|
// so these nodes are NOT VISITED YET
|
||||||
fn a_map_nodes_bool(size int) map[string]bool {
|
fn visited_init(a_graph map[string][]string) map[string]bool {
|
||||||
mut my_map := map[string]bool{} // look this map ...
|
mut array_of_keys := a_graph.keys() // get all keys of this map
|
||||||
for i in 0 .. size {
|
mut temp := map[string]bool{} // attention in these initializations with maps
|
||||||
my_map[u8(65 + i).ascii_str()] = false
|
for i in array_of_keys {
|
||||||
|
temp[i] = false
|
||||||
}
|
}
|
||||||
return my_map
|
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
|
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
|
||||||
|
@ -101,3 +101,5 @@ fn build_path_reverse(graph map[string][]string, start string, final string, vis
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//*****************************************************
|
||||||
|
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
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 evaluted
|
||||||
|
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{}
|
||||||
|
lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
mut i := 0
|
||||||
|
for (i < lenght_pq) && (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 < lenght_pq {
|
||||||
|
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 lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
for i < lenght_pq {
|
||||||
|
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 >= lenght_pq {
|
||||||
|
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 INIFINITY
|
||||||
|
mut path := []int{len: n, init: -1} // previous node of each shortest paht
|
||||||
|
|
||||||
|
// 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 adjcents 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 coluns
|
||||||
|
// 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
|
||||||
|
// allways 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,230 @@
|
||||||
|
/*
|
||||||
|
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 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 evaluted
|
||||||
|
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{}
|
||||||
|
lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
mut i := 0
|
||||||
|
for (i < lenght_pq) && (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 < lenght_pq {
|
||||||
|
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 lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
for i < lenght_pq {
|
||||||
|
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 >= lenght_pq {
|
||||||
|
// 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 INIFINITY
|
||||||
|
mut path := []int{len: n, init: -1} // previous node of each shortest paht
|
||||||
|
|
||||||
|
// 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 adjcents 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 coluns
|
||||||
|
// 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 dimmension
|
||||||
|
start_node := 0
|
||||||
|
prim_mst(graph, start_node)
|
||||||
|
}
|
||||||
|
println('\n BYE -- OK')
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************************************************
|
Loading…
Reference in New Issue