The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
graph.c
Go to the documentation of this file.
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: graph.c
8  * Author : Kyle Loudon/Dan Levin
9  * Date : Thu Jan 15 09:27:26 2015
10  * Version : 0.51
11  * ---
12  * Description: A generic graph ADT - written in ANSI C.
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 
25 #include "graph.h"
26 
27 struct Vertex_
28 {
29  void *vertexdata;
30  /* --- Collection of adjacent vertices of a vertex - i.e. its edges.. --- */
31  Slist adj_vertices;
32 };
33 
34 struct Graph_
35 {
36  int vcount;
37  int ecount;
38 
39  int (*match)(const void *key1, const void *key2);
40  void (*destroy)(void *data);
41  /* --- Collection of vertices within the graph --- */
42  Slist vertices;
43 };
44 
45 /* --- FUNCTION DEFINITIONS --- */
46 Graph GRAPHinit(int (*match)(const void *key1, const void *key2),
47  void (*destroy)(void *data))
48 {
49  Graph grtmp;
50 
51  /* Allocate memory for the graph structure */
52  if ((grtmp = (Graph)malloc(sizeof(struct Graph_))) == NULL)
53  return NULL;
54 
55  grtmp->match = match;
56  grtmp->destroy = destroy;
57  grtmp->vcount = 0;
58  grtmp->ecount = 0;
59 
60  /* Initialize the vertex list */
61  if ((grtmp->vertices = SLISTinit(NULL)) == NULL)
62  return NULL;
63 
64  /* Set the match-callback function into the vertex list */
65  SLISTsetmatch(grtmp->vertices, grtmp->match);
66 
67  return grtmp;
68 }
69 
70 void GRAPHdestroy(Graph graph)
71 {
72  Vertex vtx;
73 
74  /* Remove each vertex, destroy its data and edges - and finally the vertex itself */
75  while (SLISTsize(graph->vertices) > 0)
76  {
77  /* Remove the first vertex from the vertex collection */
78  if (SLISTremnext(graph->vertices, NULL, (void **)&vtx) == 0)
79  {
80  /* Destroy the corresponding edges for current vertex */
81  SLISTdestroy(vtx->adj_vertices);
82 
83  /* Destroy the vertex data */
84  if (graph->destroy != NULL)
85  graph->destroy(vtx->vertexdata);
86 
87  /* Destroy the vertex structure */
88  free(vtx);
89  }
90  }
91 
92  /* Destroy the vertex collection structure, which is now empty of vertices */
93  SLISTdestroy(graph->vertices);
94 
95  /* Destroy the graph structure */
96  free(graph);
97 }
98 
99 int GRAPHinsvertex(Graph graph, const void *data)
100 {
101  Vertex vtx;
102  int retval;
103 
104  /* Do not allow the insertion of duplicate vertices */
105  if (GRAPHfindvertex(graph, data) != NULL)
106  return 1;
107 
108  /* Create the new vertex */
109  if ((vtx = (Vertex)malloc(sizeof(struct Vertex_))) == NULL)
110  return -1;
111 
112  /* Insert vertex data into the new vertex */
113  vtx->vertexdata = (void *)data;
114 
115  /* Initialize/insert the adjacent vertices(=edges) for the new vertex */
116  if ((vtx->adj_vertices = SLISTinit(graph->destroy)) == NULL)
117  return -1;
118 
119  /* Set the match-callback function into the adjacent vertices(=edges) collection */
120  SLISTsetmatch(vtx->adj_vertices, graph->match);
121 
122  /* Insert the new vertex into the vertex collection */
123  if ((retval = SLISTinsnext(graph->vertices, SLISTtail(graph->vertices), vtx)) != 0)
124  return retval;
125 
126  /* Update the vertex count */
127  graph->vcount++;
128 
129  /* Everything OK */
130  return 0;
131 }
132 
133 int GRAPHinsedge(Graph graph, const void *vtxdata, const void *adjdata)
134 {
135  SlistNode node;
136  int retval;
137 
138  /* Do not allow insertion of an edge without both its vertices present.. */
139  /* Therefore - check for presence of 'adjdata' in the vertex collection.. */
140  if (GRAPHfindvertex(graph, adjdata) == NULL) /* --- Vertex not found --- */
141  return -2;
142 
143  /* Check for presence of 'vtxdata' among vertices.. */
144  if ((node = GRAPHfindvertex(graph, vtxdata)) == NULL) /* --- Vertex not found --- */
145  return -2;
146 
147  /* Do not allow insertion of duplicate edges for 'node'.. */
148  if (SLISTfindnode(((Vertex)SLISTdata(node))->adj_vertices, adjdata) != NULL) /* --- If duplicate.. --- */
149  return 1;
150 
151  /* Insert 'adjdata' into the edge collection of the vertex containing data 'vtxdata'.. */
152  if ((retval = SLISTinsnext(((Vertex)SLISTdata(node))->adj_vertices, NULL, adjdata)) !=0)
153  return retval;
154 
155  /* Update the edge count */
156  graph->ecount++;
157 
158  /* Everything OK */
159  return 0;
160 }
161 
162 int GRAPHremvertex(Graph graph, void **data)
163 {
164  SlistNode node, tmp, prev;
165  Vertex vtx;
166 
167  /* Search for vertex matching 'data'... */
168  if ((node = GRAPHfindvertex(graph, *data)) == NULL) /* Vertex not found */
169  return -2; /* Return -2 if NOT found */
170 
171  /* --- Return -3 if searched vertex is NOT isolated.. --- */
172  if (GRAPHis_isolated(graph, *data) == 0)
173  return -3;
174 
175  prev = NULL;
176 
177  for (tmp = SLISThead(graph->vertices); tmp != NULL; tmp = SLISTnext(tmp))
178  {
179  /* --- Test for a hit - if so - leave the loop.. --- */
180  if (graph->match(*data, ((Vertex)SLISTdata(tmp))->vertexdata))
181  break;
182 
183  /* Keep a pointer to the vertex BEFORE the vertex to be removed.. */
184  prev = tmp;
185  }
186 
187  /* Remove the vertex */
188  if (SLISTremnext(graph->vertices, prev, (void **)&vtx) != 0)
189  return -1;
190 
191  /* Return vertex data to caller */
192  *data = vtx->vertexdata;
193 
194  /* Destroy the (empty) edge collection.. */
195  SLISTdestroy(vtx->adj_vertices);
196 
197  /* Destroy the vertex structure */
198  free(vtx);
199 
200  /* Adjust the vertex count to account for the removed vertex */
201  graph->vcount--;
202 
203  /* Everything is OK */
204  return 0;
205 }
206 
207 int GRAPHremedge(Graph graph, void *vtxdata, void **edgedata)
208 {
209  SlistNode vtxnode;
210  int retval;
211 
212  /* If edge is NOT found.. */
213  if ((vtxnode = GRAPHfindvertex(graph, vtxdata)) == NULL)
214  return -2;
215 
216  /* Remove the second vertex(='edgedata') - from the adjacency list of the first(='vtxdata') */
217  if ((retval = SLISTfind_remove(((Vertex)SLISTdata(vtxnode))->adj_vertices, edgedata)) != 0)
218  {
219  if (retval == 1)
220  return -2;
221  else
222  return -1;
223  }
224 
225  /* Adjust the edge count to account for the removed edge */
226  graph->ecount--;
227 
228  /* Everything is OK */
229  return 0;
230 }
231 
232 void GRAPHprint(Graph graph, void (*vtxcallback)(const void *data), void (*edgecallback)(const void *data))
233 {
234  SlistNode element;
235  int nr = 1;
236 
237  for (element = SLISThead(graph->vertices); element != NULL; element = SLISTnext(element))
238  {
239  printf("\nVertex#%02d: ", nr);
240  (*vtxcallback)(((Vertex)SLISTdata(element))->vertexdata);
241  printf("\nEdges #%02d: ", nr);
242  SLISTtraverse(((Vertex)SLISTdata(element))->adj_vertices, edgecallback, SLIST_FWD);
243  nr++;
244  }
245 }
246 
247 void GRAPHtraverse(Graph graph, void (*vtxcallback)(const void *data), void (*edgecallback)(const void *data))
248 {
249  SlistNode element;
250 
251  for (element = SLISThead(graph->vertices); element != NULL; element = SLISTnext(element))
252  {
253  (*vtxcallback)(((Vertex)SLISTdata(element))->vertexdata);
254  SLISTtraverse(((Vertex)SLISTdata(element))->adj_vertices, edgecallback, SLIST_FWD);
255  }
256 }
257 
259 {
260  return ((Vertex)SLISTdata(vtxnode))->vertexdata;
261 }
262 
263 void *GRAPHgetedgedata(EdgeNode edgenode)
264 {
265  return SLISTdata(edgenode);
266 }
267 
269 {
270  return SLISThead(graph->vertices);
271 }
272 
274 {
275  if (vtxnode != NULL)
276  return SLISThead(((Vertex)SLISTdata(vtxnode))->adj_vertices);
277  return NULL;
278 }
279 
281 {
282  return SLISTnext(node);
283 }
284 
286 {
287  return SLISTnext(node);
288 }
289 
291 {
292  return SLISTsize(((Vertex)SLISTdata(vtxnode))->adj_vertices);
293 }
294 
295 int GRAPHvcount(Graph graph)
296 {
297  return graph->vcount;
298 }
299 
300 int GRAPHecount(Graph graph)
301 {
302  return graph->ecount;
303 }
304 
305 int GRAPHis_adjacent(const Graph graph, const void *vtxdata, const void *adjdata)
306 {
307  return GRAPHfindedge(graph, vtxdata, adjdata) == NULL ? 0 : 1;
308 }
309 
310 /* --- Function: int GRAPHis_isolated(const Graph graph, const void *vtxdata) --- */
311 int GRAPHis_isolated(const Graph graph, const void *data)
312 {
313  SlistNode node;
314 
315  /* --- Loop over all vertices --- */
316  for (node = SLISThead(graph->vertices); node != NULL; node = SLISTnext(node))
317  {
318  /* --- If 'data' is member of ANY adjacent vertex collection.. --- */
319  if (SLISTfindnode(((Vertex)SLISTdata(node))->adj_vertices, data) != NULL)
320  break;
321  }
322 
323  if (node != NULL) /* --- Edges directed TO 'node' exist! --- */
324  return 0;
325 
326  /* --- Search for vertex containing 'data' --- */
327  node = GRAPHfindvertex(graph, data);
328 
329  /* --- If 'node' does NOT exist.. --- */
330  if (node == NULL)
331  return 0;
332 
333  /* --- If any edges directed FROM 'node' exist.. --- */
334  if (SLISTsize(((Vertex)SLISTdata(node))->adj_vertices) != 0)
335  return 0;
336 
337  /* Vertex containing 'data' is hereby ISOLATED - return TRUE! */
338  return 1;
339 }
340 
341 /* --- Function: SlistNode GRAPHfindvertex(const Graph graph, const void *data) --- */
342 VertexNode GRAPHfindvertex(const Graph graph, const void *data)
343 {
344  SlistNode vtx = NULL;
345  Slist list;
346 
347  list = graph->vertices;
348 
349  for (vtx = SLISThead(list); vtx != NULL; vtx = SLISTnext(vtx))
350  {
351  if (graph->match(data, ((Vertex)SLISTdata(vtx))->vertexdata))
352  break;
353  }
354 
355  return vtx;
356 }
357 
358 /* --- Function: SlistNode GRAPHfindedge(const Graph graph, const void *vtxdata, const void *edgedata) --- */
359 EdgeNode GRAPHfindedge(const Graph graph, const void *vtxdata, const void *edgedata)
360 {
361  SlistNode node;
362 
363  /* --- Find the vertex containing 'vtxdata'.. --- */
364  node = GRAPHfindvertex(graph, vtxdata);
365 
366  if (node == NULL)
367  return node;
368 
369  /* Return whether the adjacent vertices of 'node'
370  - contains a vertex corresponding to 'edgedata'.. */
371  return SLISTfindnode(((Vertex)SLISTdata(node))->adj_vertices, edgedata);
372 }