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