-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finish ch11 bfs and clean up includes
- Loading branch information
Showing
11 changed files
with
555 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include <stdlib.h> | ||
|
||
#include "bfs.h" | ||
#include "graph.h" | ||
#include "../ch5/list.h" | ||
#include "../ch6/queue.h" | ||
|
||
|
||
int bfs(Graph *graph, BfsVertex *start, List *hops) { | ||
Queue queue; | ||
AdjList *adjlist, *clr_adjlist; | ||
BfsVertex *clr_vertex, *adj_vertex; | ||
ListElmt *element, *member; | ||
|
||
/* Initialize all vertices in graph */ | ||
for (element = list_head(&graph_adjlists(graph)); element != NULL; element = list_next(element)) { | ||
clr_vertex = ((AdjList *) list_data(element))->vertex; | ||
if (graph->match(clr_vertex, start)) { | ||
/* Initialize start vertex */ | ||
clr_vertex->color = gray; | ||
clr_vertex->hops = 0; | ||
} else { | ||
/* Initialize vertices other than start vertex */ | ||
clr_vertex->color = white; | ||
clr_vertex->hops = -1; | ||
} | ||
} | ||
|
||
/* Initialize the queue with the adjacency list of start vertex */ | ||
queue_init(&queue, NULL); | ||
if (graph_adjlist(graph, start, &clr_adjlist) != 0) { | ||
queue_destroy(&queue); | ||
return -1; | ||
} | ||
|
||
if (queue_enqueue(&queue, clr_adjlist) != 0) { | ||
queue_destroy(&queue); | ||
return -1; | ||
} | ||
|
||
/* Perform breadth-first search */ | ||
while (queue_size(&queue) > 0) { | ||
adjlist = queue_peek(&queue); | ||
|
||
/* Traverse each vertex in the current adjacency list */ | ||
for (member = list_head(&adjlist->adjacent); member != NULL; member = list_next(member)) { | ||
adj_vertex = list_data(member); | ||
/* Determine color of next adjacent vertex */ | ||
if (graph_adjlist(graph, adj_vertex, &clr_adjlist) != 0) { | ||
queue_destroy(&queue); | ||
return -1; | ||
} | ||
|
||
clr_vertex = clr_adjlist->vertex; | ||
|
||
/* Color each white vertex gray and enqueue its adjacency list */ | ||
if (clr_vertex->color == white) { | ||
clr_vertex->color = gray; | ||
clr_vertex->hops = ((BfsVertex *) adjlist->vertex)->hops + 1; | ||
|
||
if (queue_enqueue(&queue, clr_adjlist) != 0) { | ||
queue_destroy(&queue); | ||
return -1; | ||
} | ||
} | ||
} | ||
|
||
if (queue_dequeue(&queue, (void **) &adjlist) == 0) { | ||
((BfsVertex *) adjlist->vertex)->color = black; | ||
} else { | ||
queue_destroy(&queue); | ||
return -1; | ||
} | ||
} | ||
|
||
queue_destroy(&queue); | ||
|
||
/* Pass back the hop count for each vertex in a list */ | ||
list_init(hops, NULL); | ||
for (element = list_head(&graph_adjlists(graph)); element != NULL; element = list_next(element)) { | ||
/* Skip vertices that were not visited (those with hop counts of -1) */ | ||
clr_vertex = ((AdjList *) list_data(element))->vertex; | ||
if (clr_vertex->hops != -1) { | ||
if (list_ins_next(hops, list_tail(hops), clr_vertex) != 0) { | ||
list_destroy(hops); | ||
return -1; | ||
} | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef BFS_H | ||
#define BFS_H | ||
|
||
#include "graph.h" | ||
#include "../ch5/list.h" | ||
|
||
|
||
typedef struct BfsVertex_ { | ||
void *data; | ||
VertexColor color; | ||
int hops; | ||
} BfsVertex; | ||
|
||
|
||
int bfs(Graph *graph, BfsVertex *start, List *hops); | ||
|
||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#include <stdio.h> | ||
|
||
#include "bfs.h" | ||
|
||
|
||
int intcmp(int x, int y) { | ||
if (x == y) | ||
return 1; | ||
else | ||
return 0; | ||
} | ||
|
||
|
||
int main() { | ||
Graph graph; | ||
BfsVertex v1, v2, v3, v4, v5, v6, *bfs_vertex; | ||
List hops; | ||
ListElmt *element; | ||
|
||
int v1data = 3; | ||
int v2data = 5; | ||
int v3data = 4; | ||
int v4data = 1; | ||
int v5data = 7; | ||
int v6data = 8; | ||
|
||
v1.data = &v1data; | ||
v2.data = &v2data; | ||
v3.data = &v3data; | ||
v4.data = &v4data; | ||
v5.data = &v5data; | ||
v6.data = &v6data; | ||
|
||
graph_init(&graph, (int (*)(const void *, const void *)) intcmp, NULL); | ||
graph_ins_vertex(&graph, &v1); | ||
graph_ins_vertex(&graph, &v2); | ||
graph_ins_vertex(&graph, &v3); | ||
graph_ins_vertex(&graph, &v4); | ||
graph_ins_vertex(&graph, &v5); | ||
graph_ins_vertex(&graph, &v6); | ||
graph_ins_edge(&graph, &v1, &v2); | ||
graph_ins_edge(&graph, &v1, &v3); | ||
graph_ins_edge(&graph, &v1, &v4); | ||
graph_ins_edge(&graph, &v3, &v4); | ||
graph_ins_edge(&graph, &v4, &v5); | ||
graph_ins_edge(&graph, &v5, &v6); | ||
|
||
if (bfs(&graph, &v1, &hops) != 0) | ||
return -1; | ||
|
||
printf("Starting vertex is %d\n\n", *((int *) v1.data)); | ||
|
||
for (element = list_head(&hops); element != NULL; element = list_next(element)) { | ||
bfs_vertex = list_data(element); | ||
printf("vertex %d is %d hops from the start\n", *((int *) bfs_vertex->data), bfs_vertex->hops); | ||
} | ||
|
||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#include "graph.h" | ||
#include "../ch5/list.h" | ||
#include "../ch7/set.h" | ||
|
||
|
||
void graph_init(Graph *graph, int (*match)(const void *key1, const void *key2), | ||
void (*destroy)(void *data)) { | ||
/* Initialize graph */ | ||
graph->vcount = 0; | ||
graph->ecount = 0; | ||
graph->match = match; | ||
graph->destroy = destroy; | ||
|
||
/* Initialize list of adjacency-list structures */ | ||
list_init(&graph->adjlists, NULL); | ||
return; | ||
} | ||
|
||
|
||
void graph_destroy(Graph *graph) { | ||
AdjList *adjlist; | ||
|
||
/* Remove each adjacency-list structure and destroy its adjacency list */ | ||
while (list_size(&graph->adjlists) > 0) { | ||
if (list_rem_next(&graph->adjlists, NULL, (void **) &adjlist) == 0) { | ||
set_destroy(&adjlist->adjacent); | ||
|
||
if (graph->destroy != NULL) | ||
graph->destroy(adjlist->vertex); | ||
|
||
free(adjlist); | ||
} | ||
} | ||
|
||
/* Destroy the list of adjacency-list structures, which is now empty */ | ||
list_destroy(&graph->adjlists); | ||
memset(graph, 0, sizeof(Graph)); | ||
return; | ||
} | ||
|
||
|
||
int graph_ins_vertex(Graph *graph, const void *data) { | ||
ListElmt *element; | ||
AdjList *adjlist; | ||
int retval; | ||
|
||
/* Don't allow insertion of duplicate vertices */ | ||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data, ((AdjList *) list_data(element))->vertex)) { | ||
return 1; | ||
} | ||
} | ||
|
||
/* Insert vertex */ | ||
if ((adjlist = (AdjList *) malloc(sizeof(AdjList))) == NULL) | ||
return -1; | ||
|
||
adjlist->vertex = (void *) data; | ||
set_init(&adjlist->adjacent, graph->match, NULL); | ||
|
||
if ((retval = list_ins_next(&graph->adjlists, list_tail(&graph->adjlists), adjlist)) != 0) | ||
return retval; | ||
|
||
graph->vcount++; | ||
return 0; | ||
} | ||
|
||
|
||
int graph_ins_edge(Graph *graph, const void *data1, const void *data2) { | ||
ListElmt *element; | ||
int retval; | ||
|
||
/* Don't allow insertion of edge without both vertices being in graph */ | ||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data2, ((AdjList *) list_data(element))->vertex)) | ||
break; | ||
} | ||
|
||
if (element == NULL) | ||
return -1; | ||
|
||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data1, ((AdjList *) list_data(element))->vertex)) | ||
break; | ||
} | ||
|
||
if (element == NULL) | ||
return -1; | ||
|
||
/* Insert second vertex into adjacency list of the first */ | ||
if ((retval = set_insert(&((AdjList *) list_data(element))->adjacent, data2)) != 0) | ||
return retval; | ||
|
||
/* Adjust edge count */ | ||
graph->ecount++; | ||
return 0; | ||
} | ||
|
||
|
||
int graph_rem_vertex(Graph *graph, void **data) { | ||
ListElmt *element, *temp, *prev; | ||
AdjList *adjlist; | ||
int found; | ||
|
||
/* Traverse each adjacency list and the vertices it contains */ | ||
prev = NULL; | ||
found = 0; | ||
|
||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
/* Don't allow removal of vertex if it is in an adjacency list */ | ||
if (set_is_member(&((AdjList *) list_data(element))->adjacent, *data)) | ||
return -1; | ||
|
||
/* Keep a pointer to vertex to be removed */ | ||
if (graph->match(*data, ((AdjList *) list_data(element))->vertex)) { | ||
temp = element; | ||
found = 1; | ||
} | ||
|
||
/* Keep a pointer to the vertex before the vertex to be removed */ | ||
if (!found) | ||
prev = element; | ||
} | ||
|
||
/* Return if vertex not found */ | ||
if (!found) | ||
return -1; | ||
|
||
/* Don't allow removal of vertex if its adjacency list not empty */ | ||
if (set_size(&((AdjList *) list_data(temp))->adjacent) > 0) | ||
return -1; | ||
|
||
/* Remove vertex */ | ||
if (list_rem_next(&graph->adjlists, prev, (void **) &adjlist) != 0) | ||
return -1; | ||
|
||
/* Free storage allocated by abstract datatype */ | ||
*data = adjlist->vertex; | ||
free(adjlist); | ||
|
||
/* Adjust vertex count */ | ||
graph->vcount--; | ||
return 0; | ||
} | ||
|
||
|
||
int graph_rem_edge(Graph *graph, void *data1, void **data2) { | ||
ListElmt *element; | ||
|
||
/* Locate adjacency list for first vertex */ | ||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data1, ((AdjList *) list_data(element))->vertex)) | ||
break; | ||
} | ||
|
||
if (element == NULL) | ||
return -1; | ||
|
||
/* Remove second vertex from adjacency list of the first vertex */ | ||
if (set_remove(&((AdjList *) list_data(element))->adjacent, data2) != 0) | ||
return -1; | ||
|
||
/* Adjust edge count */ | ||
graph->ecount--; | ||
return 0; | ||
} | ||
|
||
|
||
int graph_adjlist(const Graph *graph, const void *data, AdjList **adjlist) { | ||
ListElmt *element, *prev; | ||
|
||
/* Locate adjacency list for the vertex */ | ||
prev = NULL; | ||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data, ((AdjList *) list_data(element))->vertex)) | ||
break; | ||
|
||
prev = element; | ||
} | ||
|
||
/* Return if vertex not found */ | ||
if (element == NULL) | ||
return -1; | ||
|
||
/* Pass back the adjacency list for the vertex */ | ||
*adjlist = list_data(element); | ||
return 0; | ||
} | ||
|
||
|
||
int graph_is_adjacent(const Graph *graph, const void *data1, const void *data2) { | ||
ListElmt *element, *prev; | ||
|
||
/* Locate adjacency list of first vertex */ | ||
prev = NULL; | ||
for (element = list_head(&graph->adjlists); element != NULL; element = list_next(element)) { | ||
if (graph->match(data1, ((AdjList *) list_data(element))->vertex)) | ||
break; | ||
|
||
prev = element; | ||
} | ||
|
||
/* Return if first vertex not found */ | ||
if (element == NULL) | ||
return 0; | ||
|
||
/* Return whether second vertex is in adjacency list of the first */ | ||
return set_is_member(&((AdjList *) list_data(element))->adjacent, data2); | ||
} | ||
|
Oops, something went wrong.