v / examples / graphs / minimal_spann_tree_prim.v
224 lines · 200 sloc · 6.0 KB · 9051ac8921da3e2dcbf1785ceffa7f11fea36f5c
Raw
1/*
2Exploring PRIMS,
3The data example is from
4https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
5
6by CCS
7
8PS: all the pre-requisites of Dijkstra are considered
9
10$ v run file_name.v
11
12Creating a executable
13$ v -o an_executable.EXE run file_name.v
14$ ./an_executable.EXE
15
16Code based from : Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles, Fifth Edition (English Edition)
17pseudo code written in C
18This idea is quite different: it uses a priority queue to store the current
19shortest path evaluated
20The priority queue structure built using a list to simulate
21the queue. A heap is not used in this case.
22*/
23
24// a structure
25struct NODE {
26mut:
27 data int // number of nodes
28 priority int // Lower values priority indicate ==> higher priority
29}
30
31// Function to push according to priority ... the lower priority is goes ahead
32// The "push" always sorted in pq
33fn push_pq[T](mut prior_queue []T, data int, priority int) {
34 mut temp := []T{}
35 pg_len := prior_queue.len
36
37 mut i := 0
38 for i < pg_len && priority > prior_queue[i].priority {
39 temp << prior_queue[i]
40 i++
41 }
42 // INSERTING SORTED in the queue
43 temp << NODE{data, priority} // do the copy in the right place
44 // copy the another part (tail) of original prior_queue
45 for i < pg_len {
46 temp << prior_queue[i]
47 i++
48 }
49 prior_queue = temp.clone() // I am not sure if it the right way
50}
51
52// Change the priority of a value/node ... exist a value, change its priority
53fn updating_priority[T](mut prior_queue []T, search_data int, new_priority int) {
54 mut i := 0
55 mut pg_len := prior_queue.len
56
57 for i < pg_len {
58 if search_data == prior_queue[i].data {
59 prior_queue[i] = NODE{search_data, new_priority} // do the copy in the right place
60 break
61 }
62 i++
63 // all the list was examined
64 if i >= pg_len {
65 // print('\n Priority Queue: ${prior_queue}')
66 // print('\n These data ${search_data} and ${new_priority} do not exist ... PRIORITY QUEUE problem\n')
67 // if it does not find ... then push it
68 push_pq(mut prior_queue, search_data, new_priority)
69 // exit(1) // panic(s string)
70 }
71 } // end for
72}
73
74// a single departure or remove from queue
75fn departure_priority[T](mut prior_queue []T) int {
76 mut x := prior_queue[0].data
77 prior_queue.delete(0) // or .delete_many(0, 1 )
78 return x
79}
80
81// give a NODE v, return a list with all adjacents
82// Take care, only positive EDGES
83fn all_adjacents[T](g [][]T, v int) []int {
84 mut temp := []int{}
85 for i in 0 .. (g.len) {
86 if g[v][i] > 0 {
87 temp << i
88 }
89 }
90 return temp
91}
92
93// print the costs from origin up to all nodes
94// A utility function to print the
95// constructed MST stored in parent[]
96// print all paths and their cost or weight
97fn print_solution(path []int, g [][]int) {
98 // print(' PATH: ${path} ==> ${path.len}')
99 print(' Edge \tWeight\n')
100 mut sum := 0
101 for node in 0 .. (path.len) {
102 if path[node] == -1 {
103 print('\n ${node} <== reference or start node')
104 } else {
105 print('\n ${node} <--> ${path[node]} \t${g[node][path[node]]}')
106 sum += g[node][path[node]]
107 }
108 }
109 print('\n Minimum Cost Spanning Tree: ${sum}\n\n')
110}
111
112// check structure from: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
113// s: source for all nodes
114// Two results are obtained ... cost and paths
115fn prim_mst(g [][]int, s int) {
116 mut pq_queue := []NODE{} // creating a priority queue
117 push_pq(mut pq_queue, s, 0) // goes s with priority 0
118 mut n := g.len
119
120 mut dist := []int{len: n, init: -1} // dist with -1 instead of INFINITE
121 mut path := []int{len: n, init: -1} // previous node of each shortest path
122
123 // Distance of source vertex from itself is always 0
124 dist[s] = 0
125
126 for pq_queue.len != 0 {
127 mut v := departure_priority(mut pq_queue)
128 // for all W adjacents vertices of v
129 mut adjs_of_v := all_adjacents(g, v) // all_ADJ of v ....
130 // print('\n :${dist} :: ${pq_queue}')
131 // print('\n ADJ ${v} is ${adjs_of_v}')
132 mut new_dist := 0
133 for w in adjs_of_v {
134 new_dist = dist[v] + g[v][w]
135
136 if dist[w] == -1 {
137 dist[w] = g[v][w]
138 push_pq(mut pq_queue, w, dist[w])
139 path[w] = v // collecting the previous node -- lowest weight
140 }
141
142 if dist[w] > new_dist {
143 dist[w] = g[v][w] // new_dist//
144 updating_priority(mut pq_queue, w, dist[w])
145 path[w] = v // father / previous node
146 }
147 }
148 }
149
150 // print('\n \n Previous node of shortest path: ${path}')
151 // print_paths_dist(path , dist)
152 print_solution(path, g)
153}
154
155/*
156Solution Expected graph_02
157Edge Weight
1580 - 1 2
1591 - 2 3
1600 - 3 6
1611 - 4 5
162*/
163
164fn main() {
165 // adjacency matrix = cost or weight
166 graph_01 := [
167 [0, 4, 0, 0, 0, 0, 0, 8, 0],
168 [4, 0, 8, 0, 0, 0, 0, 11, 0],
169 [0, 8, 0, 7, 0, 4, 0, 0, 2],
170 [0, 0, 7, 0, 9, 14, 0, 0, 0],
171 [0, 0, 0, 9, 0, 10, 0, 0, 0],
172 [0, 0, 4, 14, 10, 0, 2, 0, 0],
173 [0, 0, 0, 0, 0, 2, 0, 1, 6],
174 [8, 11, 0, 0, 0, 0, 1, 0, 7],
175 [0, 0, 2, 0, 0, 0, 6, 7, 0],
176 ]
177
178 graph_02 := [
179 [0, 2, 0, 6, 0],
180 [2, 0, 3, 8, 5],
181 [0, 3, 0, 0, 7],
182 [6, 8, 0, 0, 9],
183 [0, 5, 7, 9, 0],
184 ]
185 // data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
186 /*
187 The graph:
188 2 3
189 (0)--(1)--(2)
190 | / \ |
191 6| 8/ \5 |7
192 | / \ |
193 (3)-------(4)
194 9
195 Let us create following weighted graph
196 From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
197 10
198 0--------1
199 | \ |
200 6| 5\ |15
201 | \ |
202 2--------3
203 4
204 */
205 graph_03 := [
206 [0, 10, 6, 5],
207 [10, 0, 0, 15],
208 [6, 0, 0, 4],
209 [5, 15, 4, 0],
210 ]
211
212 // To find number of columns
213 // mut cols := an_array[0].len
214 mut graph := [][]int{} // the graph: adjacency matrix
215 // for index, g_value in [graph_01, graph_02, graph_03] {
216 for index, g_value in [graph_01, graph_02, graph_03] {
217 println('\n Minimal Spanning Tree of graph ${index + 1} using PRIM algorithm')
218 graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
219 // starting by node x ... see the graphs dimensions
220 start_node := 0
221 prim_mst(graph, start_node)
222 }
223 println('\n BYE -- OK')
224}
225