Initial Commit
This commit is contained in:
407
OU4/graph2.c
Normal file
407
OU4/graph2.c
Normal file
@@ -0,0 +1,407 @@
|
||||
#include <stdio.h>
|
||||
#include <dlist.h>
|
||||
#include <graph.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* graph2.c: Implementation of a dlist based graph for "Obligatorisk uppgift 4" in the "Datastructures and
|
||||
* algorithms" course at the Department of Computing Science, Umea University.
|
||||
*
|
||||
* Authors: Marc Meunier tfy22mmr
|
||||
* Ellen Horneij tfy22ehj
|
||||
* Jakob Nyström tfy22jnm
|
||||
*
|
||||
* Version information:
|
||||
* v1.0 2025-05-25: First public version.
|
||||
*
|
||||
*/
|
||||
|
||||
// ===========INTERNAL DATA TYPES ============
|
||||
|
||||
struct graph
|
||||
{
|
||||
dlist *nodes; // The graph nodes are stored in a directed list
|
||||
int max_nodes;
|
||||
// int connected;
|
||||
};
|
||||
|
||||
struct node
|
||||
{
|
||||
const char *value;
|
||||
bool seen;
|
||||
dlist *edge;
|
||||
};
|
||||
|
||||
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
|
||||
|
||||
/**
|
||||
* node_entry_kill() - Return the memory allocated to a node entry.
|
||||
* @e: The entry to deallocate.
|
||||
*
|
||||
* Returns: Nothing.
|
||||
*/
|
||||
void node_entry_kill(void *v)
|
||||
{
|
||||
node *n = v;
|
||||
free((void*)n->value); // Cast away const and free the string
|
||||
dlist_kill(n->edge); // kills list
|
||||
free(n); // frees memory
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_entry_create() - Allocate and populate a graph entry.
|
||||
* @key: A pointer to a function to be used to compare keys.
|
||||
* @value: A pointer to a function (or NULL) to be called to
|
||||
* de-allocate memory for keys on remove/kill.
|
||||
*
|
||||
* Returns: A pointer to the newly created graph entry.
|
||||
*/
|
||||
node *node_entry_create(const char *value, int max_node)
|
||||
{
|
||||
// Allocate space for a graph entry. Use calloc as a defensive
|
||||
node *n = calloc(1, sizeof(*n));
|
||||
|
||||
// Populate the entry.
|
||||
char *tmp = malloc(strlen(value) + 1);
|
||||
if (tmp != NULL)
|
||||
{
|
||||
strcpy(tmp, value);
|
||||
n->value = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle memory allocation failure
|
||||
free(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set status to false, and create the list of edges
|
||||
n->seen = false;
|
||||
n->edge = dlist_empty(NULL);
|
||||
return n;
|
||||
}
|
||||
|
||||
// =================== GRAPH STRUCTURE INTERFACE ======================
|
||||
|
||||
/**
|
||||
* nodes_are_equal() - Check whether two nodes are equal.
|
||||
* @n1: Pointer to node 1.
|
||||
* @n2: Pointer to node 2.
|
||||
*
|
||||
* Returns: true if the nodes are considered equal, otherwise false.
|
||||
*
|
||||
*/
|
||||
bool nodes_are_equal(const node *n1, const node *n2)
|
||||
{
|
||||
if (n1 == NULL || n2 == NULL)
|
||||
{
|
||||
return n1 == n2;
|
||||
}
|
||||
// compares string values of nodes
|
||||
return strcmp(n1->value, n2->value) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_empty() - Create an empty graph.
|
||||
* @max_nodes: The maximum number of nodes the graph can hold.
|
||||
*
|
||||
* Returns: A pointer to the new graph.
|
||||
*/
|
||||
graph *graph_empty(int max_nodes)
|
||||
{
|
||||
// Allocate the graph
|
||||
graph *g = calloc(1, sizeof(graph));
|
||||
|
||||
// Create the list to hold the graph_entry-ies.
|
||||
g->nodes = dlist_empty(node_entry_kill);
|
||||
g->max_nodes = max_nodes;
|
||||
return g;
|
||||
}
|
||||
|
||||
/*
|
||||
* graph_is_empty() - Check if a graph is empty, i.e. has no nodes.
|
||||
* @g: Graph to check.
|
||||
*
|
||||
* Returns: True if graph is empty, otherwise false.
|
||||
*/
|
||||
bool graph_is_empty(const graph *g)
|
||||
{
|
||||
return dlist_is_empty(g->nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_insert_node() - Inserts a node with the given name into the graph.
|
||||
* @g: Graph to manipulate.
|
||||
* @s: Node name.
|
||||
*
|
||||
* Creates a new node with a copy of the given name and puts it into
|
||||
* the graph.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*/
|
||||
graph *graph_insert_node(graph *g, const char *s)
|
||||
{
|
||||
// create node
|
||||
node *n = node_entry_create(s, g->max_nodes);
|
||||
n->seen = false;
|
||||
|
||||
// get start position of list
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
|
||||
// iterate over list
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
// check node already exists
|
||||
node *m = dlist_inspect(g->nodes, pos);
|
||||
if (nodes_are_equal(n, m))
|
||||
{
|
||||
node_entry_kill(n);
|
||||
return g;
|
||||
}
|
||||
// go to next position
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
// inserts node into list
|
||||
dlist_insert(g->nodes, n, dlist_first(g->nodes));
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_has_edges() - Check if a graph has any edges.
|
||||
* @g: Graph to check.
|
||||
*
|
||||
* Returns: True if graph has any edges, otherwise false.
|
||||
*/
|
||||
bool graph_has_edges(const graph *g)
|
||||
{
|
||||
// get start position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
|
||||
// check for edges for every node
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
node *n = dlist_inspect(g->nodes, pos);
|
||||
if (!dlist_is_empty(n->edge))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// go to next position
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_find_node() - Find a node stored in the graph.
|
||||
* @g: Graph to manipulate.
|
||||
* @s: Node identifier, e.g. a char *.
|
||||
*
|
||||
* Returns: A pointer to the found node, or NULL.
|
||||
*/
|
||||
node *graph_find_node(const graph *g, const char *s)
|
||||
{
|
||||
// get start position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
node *n = dlist_inspect(g->nodes, pos);
|
||||
// compare value with the one we are looking for
|
||||
if (strcmp(n->value, s) == 0)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
// go to next position
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* graph_node_is_seen() - Return the seen status for a node.
|
||||
* @g: Graph storing the node.
|
||||
* @n: Node in the graph to return seen status for.
|
||||
*
|
||||
* Returns: The seen status for the node.
|
||||
*/
|
||||
bool graph_node_is_seen(const graph *g, const node *n)
|
||||
{
|
||||
// get start position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
node *e = dlist_inspect(g->nodes, pos);
|
||||
// if node is one we are looking for, check seen status
|
||||
if (nodes_are_equal(e, n))
|
||||
{
|
||||
return e->seen;
|
||||
}
|
||||
// increment position
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_node_set_seen() - Set the seen status for a node.
|
||||
* @g: Graph storing the node.
|
||||
* @n: Node in the graph to set seen status for.
|
||||
* @s: Status to set.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*/
|
||||
graph *graph_node_set_seen(graph *g, node *n, bool seen)
|
||||
{
|
||||
// get beginning position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
node *e = dlist_inspect(g->nodes, pos);
|
||||
// check if nodes are same as one we look for
|
||||
if (nodes_are_equal(e, n))
|
||||
{
|
||||
// set node to seen
|
||||
e->seen = seen;
|
||||
break;
|
||||
}
|
||||
// increment pos in list
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_reset_seen() - Reset the seen status on all nodes in the graph.
|
||||
* @g: Graph to modify.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*/
|
||||
graph *graph_reset_seen(graph *g)
|
||||
{
|
||||
// get starting position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
// if node is seen, reset
|
||||
node *n = dlist_inspect(g->nodes, pos);
|
||||
if (n->seen == true)
|
||||
{
|
||||
n->seen = false;
|
||||
}
|
||||
// increment over list
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_insert_edge() - Insert an edge into the graph.
|
||||
* @g: Graph to manipulate.
|
||||
* @n1: Source node (pointer) for the edge.
|
||||
* @n2: Destination node (pointer) for the edge.
|
||||
*
|
||||
* NOTE: Undefined unless both nodes are already in the graph.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*/
|
||||
graph *graph_insert_edge(graph *g, node *n1, node *n2)
|
||||
{
|
||||
// get starting position
|
||||
dlist_pos pos = dlist_first(n1->edge);
|
||||
while (!dlist_is_end(n1->edge, pos))
|
||||
{
|
||||
node *n = dlist_inspect(n1->edge, pos);
|
||||
// check if node already is in edge list
|
||||
if (nodes_are_equal(n2, n))
|
||||
{
|
||||
return g;
|
||||
}
|
||||
// increment to next position
|
||||
pos = dlist_next(n1->edge, pos);
|
||||
}
|
||||
// inserts the edge in node list.
|
||||
dlist_insert(n1->edge, n2, dlist_first(n1->edge));
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_neighbours() - Return a list of neighbour nodes.
|
||||
* @g: Graph to inspect.
|
||||
* @n: Node to get neighbours for.
|
||||
*
|
||||
* Returns: A pointer to a list of nodes. Note: The list must be
|
||||
* dlist_kill()-ed after use.
|
||||
*/
|
||||
dlist *graph_neighbours(const graph *g, const node *n)
|
||||
{
|
||||
// Create a new list
|
||||
dlist *copy = dlist_empty(NULL);
|
||||
|
||||
if (n == NULL || n->edge == NULL) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Copy nodes to new list, so list can be dlost_kill-ed outside.
|
||||
dlist_pos pos = dlist_first(n->edge);
|
||||
while (!dlist_is_end(n->edge, pos)) {
|
||||
void *node = dlist_inspect(n->edge, pos);
|
||||
dlist_insert(copy, node, dlist_first(copy));
|
||||
pos = dlist_next(n->edge, pos);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_kill() - Destroy a given graph.
|
||||
* @g: Graph to destroy.
|
||||
*
|
||||
* Return all dynamic memory used by the graph.
|
||||
*
|
||||
* Returns: Nothing.
|
||||
*/
|
||||
void graph_kill(graph *g)
|
||||
{
|
||||
dlist_kill(g->nodes);
|
||||
free(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_print() - Iterate over the graph elements and print their values.
|
||||
* @g: Graph to inspect.
|
||||
*
|
||||
* Iterates over the graph and prints its contents.
|
||||
*
|
||||
* Returns: Nothing.
|
||||
*/
|
||||
void graph_print(const graph *g)
|
||||
{
|
||||
// get first position
|
||||
dlist_pos pos = dlist_first(g->nodes);
|
||||
// iterate and prints node
|
||||
while (!dlist_is_end(g->nodes, pos))
|
||||
{
|
||||
node *n = dlist_inspect(g->nodes, pos);
|
||||
printf("%s to nodes: ", (char *)n->value);
|
||||
|
||||
// get edges pos, and print edges of node.
|
||||
dlist_pos pos_edge = dlist_first(n->edge);
|
||||
while (!dlist_is_end(n->edge, pos_edge))
|
||||
{
|
||||
node *e = dlist_inspect(n->edge, pos_edge);
|
||||
printf("%s,", (char *)e->value);
|
||||
|
||||
// goes to next edge in list
|
||||
pos_edge = dlist_next(n->edge, pos_edge);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// goes to next node in list.
|
||||
pos = dlist_next(g->nodes, pos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user