Skip to content

Commit

Permalink
Finish ch11 bfs and clean up includes
Browse files Browse the repository at this point in the history
  • Loading branch information
davidxia committed Dec 30, 2012
1 parent 07bb3a3 commit b3249b8
Show file tree
Hide file tree
Showing 11 changed files with 555 additions and 79 deletions.
93 changes: 93 additions & 0 deletions algos_with_c/ch11/bfs.c
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;
}

18 changes: 18 additions & 0 deletions algos_with_c/ch11/bfs.h
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

60 changes: 60 additions & 0 deletions algos_with_c/ch11/bfs_test.c
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;
}

213 changes: 213 additions & 0 deletions algos_with_c/ch11/graph.c
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);
}

Loading

0 comments on commit b3249b8

Please sign in to comment.