The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
algo.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: algo.c
8  * Author : Dan Levin
9  * Date : Mon Feb 16 10:08:33 2015
10  * Version : 0.51
11  * ---
12  * Description: Miscellaneous algorithms
13  *
14  * Date Revision message
15  * 150331 This code ready for version 0.51
16  *
17  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "algo.h"
25 
26 #ifndef OK
27 #define OK 0
28 #endif
29 
30 #ifndef TRUE
31 #define TRUE 1
32 #endif
33 
34 #ifndef FALSE
35 #define FALSE 0
36 #endif
37 
38 /* --- STATIC FUNCTION DECLARATIONS --- */
39 
40 static void relax(DspVertexdata u, DspVertexdata v, double weight);
41 static int dfs_main(Graph gr, VertexNode vtx, Slist *ordered);
42 
43 /* --- FUNCTION DEFINITIONS --- */
44 
45 int ALGOdsp(Graph gr, const DspVertexdata start, Slist *spath, int (*match)(const void *key1, const void *key2))
46 {
47  DspVertexdata vtxdata, edgedata, mindata;
48  VertexNode vtxnode, minnode;
49  EdgeNode edgenode;
50  double minimum;
51  int found, i;
52 
53  /* --- Initialize all of the vertices in the graph --- */
54  found = FALSE;
55 
56  /* Loop over list of vertices... */
57  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
58  {
59  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
60 
61  if (match(vtxdata, start))
62  {
63  /* --- Initialize the start vertex --- */
64  vtxdata->color = white;
65  vtxdata->distance = 0;
66  vtxdata->parent = NULL;
67  found = TRUE;
68  }
69  else
70  {
71  /* --- Initialize vertices other than the start vertex --- */
72  vtxdata->color = white;
73  vtxdata->distance = DBL_MAX;
74  vtxdata->parent = NULL;
75  }
76  }
77 
78  /* --- Return if the start vertex was not found --- */
79  if (found == FALSE)
80  return -1;
81 
82  /* --- Use Dijkstra's algorithm to compute shortest paths from start vertex --- */
83  i = 0;
84 
85  while (i < GRAPHvcount(gr))
86  {
87  /* --- Select the white vertex with the smallest shortest-path estimate --- */
88  minimum = DBL_MAX;
89 
90  /* Loop over list of vertices... */
91  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
92  {
93  /* Extract vertex data from current node.. */
94  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
95  /* If current vertex is white - and its distance < minimum.. */
96  if (vtxdata->color == white && vtxdata->distance < minimum)
97  {
98  minimum = vtxdata->distance; /* Set minimum to distance field of vertex */
99  minnode = vtxnode; /* Save node with smallest distance value - so far.. */
100  }
101  }
102 
103  /* --- Color the selected(=minimum)vertex black --- */
104  mindata = (DspVertexdata)GRAPHgetvertexdata(minnode);
105  mindata->color = black;
106 
107  /* --- Traverse each vertex adjacent to the selected vertex node(='minnode') above --- */
108  for (edgenode = GRAPHgetedgehead(minnode); edgenode != NULL; edgenode = GRAPHgetedgenext(edgenode))
109  {
110  /* Extract data from edge node */
111  edgedata = GRAPHgetedgedata(edgenode);
112 
113  /* --- Find the matching vertex for current edge node in the list of vertices --- */
114  if ((vtxnode = GRAPHfindvertex(gr, edgedata)) != NULL)
115  {
116  /* Extract data from vertex found */
117  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
118  /* Relax data for 2 vertices - 'minnode' and 'vtxnode' */
119  relax(mindata, vtxdata, edgedata->weight);
120  }
121  }
122  /* --- Prepare to select the next vertex --- */
123  i++;
124  }
125 
126  /* --- Load the vertices with their path information into a list --- */
127  *spath = SLISTinit(NULL);
128 
129  /* Loop over list of vertices... */
130  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
131  {
132  /* --- Load each black vertex from graph into the list --- */
133  /* Extract data of current vertex node */
134  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
135 
136  if (vtxdata->color == black) /* If current vertex is black */
137  {
138  if (SLISTinsnext(*spath, SLISTtail(*spath), vtxdata) != OK)
139  {
140  SLISTdestroy(*spath);
141  *spath = NULL;
142  return -1; /* Return error.. */
143  }
144  }
145  }
146 
147  /* Everything is OK */
148  return OK;
149 }
150 
151 static void relax(DspVertexdata u, DspVertexdata v, double weight)
152 {
153  /* --- Relax an edge between two vertices u and v --- */
154  if (v->distance > u->distance + weight)
155  {
156  v->distance = u->distance + weight; /* Update the 'distance' field of 'v' */
157  v->parent = u; /* Record the parent of 'v' */
158  }
159 }
160 
161 int ALGOmst(Graph gr, const MstVertexdata start, Slist *span, int (*match)(const void *key1, const void *key2))
162 {
163  MstVertexdata vtxdata, edgedata, mindata;
164  VertexNode vtxnode, minnode;
165  EdgeNode edgenode;
166  double minimum;
167  int found, i;
168 
169  /* --- Initialize all of the vertices in the graph --- */
170  found = FALSE;
171 
172  /* Loop over list of vertices... */
173  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
174  {
175  /* Extract data of current vertex.. */
176  vtxdata = (MstVertexdata)GRAPHgetvertexdata(vtxnode);
177 
178  if (match(vtxdata, start)) /* If current vertex equals start node.. */
179  {
180  /* --- Initialize the start vertex --- */
181  vtxdata->color = white;
182  vtxdata->key = 0;
183  vtxdata->parent = NULL;
184  found = TRUE;
185  }
186  else
187  {
188  /* --- Initialize vertices other than the start vertex --- */
189  vtxdata->color = white;
190  vtxdata->key = DBL_MAX;
191  vtxdata->parent = NULL;
192  }
193  }
194 
195  /* --- Return if the start vertex was not found --- */
196  if (found == FALSE)
197  return -1;
198 
199  /* --- Use Prim's algorithm to compute Minimal Spanning Tree --- */
200  i = 0;
201 
202  while (i < GRAPHvcount(gr))
203  {
204  /* --- Select the white vertex with the smallest key value --- */
205  minimum = DBL_MAX;
206 
207  /* Loop over list of vertices... */
208  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
209  {
210  /* Extract data of current vertex.. */
211  vtxdata = (MstVertexdata)GRAPHgetvertexdata(vtxnode);
212 
213  /* If color of current vertex is white - and - 'key' < 'minimum'.. */
214  if (vtxdata->color == white && vtxdata->key < minimum)
215  {
216  minimum = vtxdata->key; /* Set 'minimum' to 'key' value of current vertex */
217  minnode = vtxnode; /* Save node with smallest key value - so far.. */
218  }
219  }
220 
221  /* --- Color the selected(=minimum)vertex black --- */
222  mindata = (MstVertexdata)GRAPHgetvertexdata(minnode);
223  mindata->color = black;
224 
225  /* --- Traverse each vertex adjacent to the selected vertex node(='minnode') above --- */
226  for (edgenode = GRAPHgetedgehead(minnode); edgenode != NULL; edgenode = GRAPHgetedgenext(edgenode))
227  {
228  /* Extract data of current (adjacent) edge node */
229  edgedata = GRAPHgetedgedata(edgenode);
230 
231  /* --- Find the matching vertex for current edge node in the list of vertices --- */
232  if ((vtxnode = GRAPHfindvertex(gr, edgedata)) != NULL)
233  {
234  /* Extract data of vertex found.. */
235  vtxdata = (MstVertexdata)GRAPHgetvertexdata(vtxnode);
236  /* If color of vertex found is white - and -
237  'key' value is > 'weight' of current edge node */
238  if (vtxdata->color == white && edgedata->weight < vtxdata->key)
239  {
240  vtxdata->key = edgedata->weight; /* Set 'key' field of vertex found to weight of current edge */
241  vtxdata->parent = mindata; /* Record parent in vertex found - to data of 'minnode' selected above */
242  }
243  }
244  }
245  /* --- Prepare to select the next vertex --- */
246  i++;
247  }
248 
249  /* --- Load the vertices with their path information into a list --- */
250  *span = SLISTinit(NULL);
251 
252  /* Loop over list of vertices... */
253  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
254  {
255  /* --- Load each black vertex from graph into the list --- */
256  vtxdata = (MstVertexdata)GRAPHgetvertexdata(vtxnode);
257 
258  if (vtxdata->color == black)
259  {
260  if (SLISTinsnext(*span, SLISTtail(*span), vtxdata) != OK)
261  {
262  SLISTdestroy(*span);
263  *span = NULL;
264  return -1; /* Return error.. */
265  }
266  }
267  }
268 
269  return OK;
270 }
271 
272 int ALGOtsp(Slist vertices, const TspVertexdata start, Slist *tour, int (*match)(const void *key1, const void *key2))
273 {
274  TspVertexdata tsp_vtx, tsp_start, selection;
275  SlistNode node;
276  double min, distance, x, y;
277  int found, i;
278 
279  /* Initialize the list for the tour */
280  *tour = SLISTinit(NULL);
281 
282  /* --- Initialize all of the vertices in the (complete) graph --- */
283  found = FALSE;
284 
285  /* Loop over the list of vertices.. */
286  for (node = SLISThead(vertices); node != NULL; node = SLISTnext(node))
287  {
288  /* Extract data of current node.. */
289  tsp_vtx = SLISTdata(node);
290 
291  if (match(tsp_vtx, start))
292  {
293 
294  /* Start the tour at 'start' vertex.. */
295  if (SLISTinsnext(*tour, SLISTtail(*tour), tsp_vtx) != OK )
296  {
297  SLISTdestroy(*tour);
298  return -1;
299  }
300 
301  /* Save the start vertex - and its coordinates.. */
302  tsp_start = tsp_vtx;
303  x = tsp_vtx->x;
304  y = tsp_vtx->y;
305 
306  /* Color the vertex black */
307  tsp_vtx->color = black;
308  found = TRUE;
309  }
310  else
311  {
312  /* Color all other vertices white */
313  tsp_vtx->color = white;
314  }
315  } /* Initialization done! */
316 
317  /* Return if start vertex not found.. */
318  if (found == FALSE)
319  {
320  SLISTdestroy(*tour);
321  return -1;
322  }
323 
324 
325  /* --- Use the nearest-neighbor heuristic to compute the tour --- */
326  i = 0;
327 
328  while (i < SLISTsize(vertices)-1)
329  {
330  /* --- Select the white vertex closest to the previous tour vertex --- */
331  min = DBL_MAX;
332  /* Loop over list of vertices.. */
333  for (node = SLISThead(vertices); node != NULL; node = SLISTnext(node))
334  {
335  /* Extract data from current node.. */
336  tsp_vtx = SLISTdata(node);
337 
338  /* If current vertex is white.. */
339  if (tsp_vtx->color == white)
340  {
341  /* Compute the distance between current vertex and previous one on tour.. */
342  distance = sqrt(pow((tsp_vtx->x - x), 2.0) + pow((tsp_vtx->y - y), 2.0));
343 
344  /* If closer - save it.. */
345  if (distance < min)
346  {
347  min = distance;
348  selection = tsp_vtx;
349  }
350  }
351  } /* End-while. Shortest distance to previous vertex computed.. */
352 
353  /* Save the coordinates of selected(=closest) vertex */
354  x = selection->x;
355  y = selection->y;
356  /* Color selected vertex black.. */
357  selection->color = black;
358 
359  /* Insert selected vertex into the tour.. */
360  if (SLISTinsnext(*tour, SLISTtail(*tour), selection) != OK)
361  {
362  SLISTdestroy(*tour);
363  return -1;
364  }
365 
366  /* Increment loop variable 'i' - to prepare for next tour vertex */
367  i++;
368  }
369 
370  /* Insert the start vertex again - to complete the tour.. */
371  if (SLISTinsnext(*tour, SLISTtail(*tour), tsp_start) != OK)
372  {
373  SLISTdestroy(*tour);
374  return -1;
375  }
376 
377  return OK;
378 }
379 
380 int ALGObfs(Graph gr, const BfsVertexdata start, Slist *hops, int (*match)(const void *key1, const void *key2))
381 {
382  Queue queue;
383  BfsVertexdata vtxdata, adjvtxdata, edgedata;
384  VertexNode vtxnode, vtxnode2;
385  EdgeNode edgenode;
386 
387  /* --- Initialize all of the vertices in the graph --- */
388  /* Loop over list of vertices... */
389  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
390  {
391  /* Extract data of current vertex node.. */
392  vtxdata = (BfsVertexdata)GRAPHgetvertexdata(vtxnode);
393 
394  if (match(vtxdata, start)) /* If current vertex node matches start node */
395  {
396  /* --- Initialize the start vertex --- */
397  vtxdata->color = gray;
398  vtxdata->hops = 0;
399  }
400  else
401  {
402  /* --- Initialize vertices other than the start vertex --- */
403  vtxdata->color = white;
404  vtxdata->hops = -1;
405  }
406  }
407 
408  /* Initialize the queue with the start vertex */
409  queue = QUEUEinit(NULL); /* Create the queue.. */
410 
411  /* Find the vertex node matching start vertex data */
412  if ((vtxnode = GRAPHfindvertex(gr, start)) == NULL)
413  {
414  QUEUEdestroy(queue);
415  return -1;
416  }
417 
418  /* Enqueue this vertex node found.. */
419  if (QUEUEenqueue(queue, vtxnode) != OK )
420  {
421  QUEUEdestroy(queue);
422  return -1;
423  }
424 
425  /* Now, we start the Breadth-First Search */
426  while (QUEUEsize(queue) > 0)
427  {
428  /* Peek at the front of the queue.. */
429  vtxnode = (VertexNode)QUEUEpeek(queue);
430  /* ..and extract corresponding data */
431  vtxdata = GRAPHgetvertexdata(vtxnode);
432 
433  /* Traverse each node in current edge(=adjacency)list.. */
434  for (edgenode = GRAPHgetedgehead(vtxnode); edgenode != NULL; edgenode = GRAPHgetedgenext(edgenode))
435  {
436  /* Extract data from current edge node.. */
437  edgedata = GRAPHgetedgedata(edgenode);
438 
439  /* Find the matching vertex of edge node - in list of vertices.. */
440  if ((vtxnode2 = GRAPHfindvertex(gr, edgedata)) == NULL)
441  {
442  QUEUEdestroy(queue);
443  return -1;
444  }
445 
446  /* Determine the color of current (adjacent) vertex found.. */
447  adjvtxdata = GRAPHgetvertexdata(vtxnode2);
448 
449  if (adjvtxdata->color == white) /* If color is white.. */
450  {
451  adjvtxdata->color = gray; /* Update color to gray.. */
452  adjvtxdata->hops = vtxdata->hops+1; /* Increment 'hops' by 1 - rel. 'hops' in front node in 'queue' */
453 
454  /* Enqueue this newly updated node - into the (end of) queue */
455  if (QUEUEenqueue(queue, vtxnode2) != OK)
456  {
457  QUEUEdestroy(queue);
458  return -1;
459  }
460  }
461  } /* End of for-loop. Traversal of current adjacency list done.. */
462 
463  /* Dequeue the front node from queue - and color its vertex black.. */
464  if (QUEUEdequeue(queue, (void **)&vtxnode) == OK)
465  {
466  vtxdata->color = black;
467  }
468  else
469  {
470  QUEUEdestroy(queue);
471  return -1;
472  }
473  } /* End-while */
474 
475  /* Our queue is no longer needed - i.e. destroy it! */
476  QUEUEdestroy(queue);
477 
478  /* Pass back the hop count for each vertex in a list */
479  *hops = SLISTinit(NULL);
480 
481  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
482  {
483  vtxdata = GRAPHgetvertexdata(vtxnode);
484 
485  /* Skip the vertices with hop counts of -1 - i.e. vertices not visited.. */
486  if (vtxdata->hops != -1)
487  {
488  if (SLISTinsnext(*hops, SLISTtail(*hops), vtxdata) != OK)
489  {
490  SLISTdestroy(*hops);
491  return -1;
492  }
493  }
494  }
495 
496  return OK;
497 }
498 
499 int ALGOdfs(Graph gr, Slist *ordered)
500 {
501  DfsVertexdata vtxdata;
502  VertexNode vtxnode;
503 
504  /* Initialize all the vertices in the graph */
505  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
506  {
507  /* Extract data of current node */
508  vtxdata = GRAPHgetvertexdata(vtxnode);
509  /* Set color to white */
510  vtxdata->color = white;
511  }
512 
513  /* Initialize a list.. */
514  *ordered = SLISTinit(NULL);
515 
516  /* --- Perform the Depth-First Search --- */
517  for (vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; vtxnode = GRAPHgetvertexnext(vtxnode))
518  {
519  /* Extract data of current node.. */
520  vtxdata = GRAPHgetvertexdata(vtxnode);
521 
522  /* Ensure that all components of an unconnected graph is searched.. */
523  if (vtxdata->color == white)
524  {
525  if (dfs_main(gr, vtxnode, ordered) != OK)
526  {
527  SLISTdestroy(*ordered);
528  return -1;
529  }
530  }
531  }
532 
533  return OK;
534 }
535 
536 static int dfs_main(Graph gr, VertexNode vtxnode, Slist *ordered)
537 {
538  VertexNode vnode;
539  EdgeNode enode;
540  DfsVertexdata vtxdata, vtxdata2, edgedata;
541 
542  /* Extract data of vertex node received in arg. 2 - and color the vertex gray.. */
543  vtxdata = GRAPHgetvertexdata(vtxnode);
544  vtxdata->color = gray;
545  /* ..and traverse its adjacency list */
546  for (enode = GRAPHgetedgehead(vtxnode); enode != NULL; enode = GRAPHgetvertexnext(enode))
547  {
548  /* Extract data of current edge node (- in current adjacency list).. */
549  edgedata = GRAPHgetedgedata(enode);
550  /* Find the matching vertex node in list of vertices.. */
551  if ((vnode = GRAPHfindvertex(gr, edgedata)) == NULL)
552  return -1;
553  /* Extract data of this vertex node found.. */
554  vtxdata2 = GRAPHgetvertexdata(vnode);
555 
556  /* If this node is white.. */
557  if (vtxdata2->color == white)
558  {
559  /* Make a recursive call.. */
560  if (dfs_main(gr, vnode, ordered) != OK)
561  return -1;
562  }
563  }
564 
565  /* Color the argument vertex black.. */
566  vtxdata->color = black;
567  /* ..and insert it as the first into the list */
568  if (SLISTinsnext(*ordered, NULL, vtxdata) != OK)
569  return -1;
570 
571  return OK;
572 }