Initial Commit
This commit is contained in:
484
OU4/graph.c
Normal file
484
OU4/graph.c
Normal file
@@ -0,0 +1,484 @@
|
||||
#include <stdio.h>
|
||||
#include <array_2d.h> // ska innehålla array_2d implementation
|
||||
#include <graph.h>
|
||||
#include <dlist.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* graph.c: Implementation of a 2-dimensional array based graph for "Obligatorisk uppgift 4" in the "Datastructures and
|
||||
* algorithms" course at the Department of Computing Science, Umea University.
|
||||
*
|
||||
* Authors: Jakob Nyström tfy22jnm
|
||||
* Ellen Horneij tfy22ehj
|
||||
* Marc Meunier tfy22mmr
|
||||
*
|
||||
* Version information:
|
||||
* v1.0 2025-05-25: First public version.
|
||||
*
|
||||
*/
|
||||
|
||||
// ===========INTERNAL DATA TYPES ============
|
||||
|
||||
// Graph contains the matrix with nodes and edges, total number of nodes ans edges and
|
||||
struct graph
|
||||
{
|
||||
array_2d *entries;
|
||||
int nr_of_nodes;
|
||||
int nr_of_edges;
|
||||
int max_nodes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Node entry contains the value of the node, it's position and it's seen status
|
||||
*/
|
||||
struct node
|
||||
{
|
||||
const char *value;
|
||||
int position;
|
||||
bool seen;
|
||||
};
|
||||
|
||||
// =================== NODE COMPARISON FUNCTION ======================
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Uses strcomp to compare the nodes
|
||||
int cmp = strcmp(n1->value, n2->value);
|
||||
|
||||
// Returns true if strcomp returns 0 meaning that the nodes are equal, if else false
|
||||
if (cmp == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// ===========INTERNAL FUNCTION IMPLEMENTATIONS ============
|
||||
|
||||
/**
|
||||
* node_create() - Allocates the memory and creates a node entry
|
||||
* @s: the value of the node
|
||||
*
|
||||
* Returns: The pointer to node entry with value s
|
||||
*/
|
||||
node *node_create(const char *s)
|
||||
{
|
||||
// Allocate the memory for the node entry
|
||||
node *n = calloc(1, sizeof(*n));
|
||||
|
||||
// Populate the entry.
|
||||
n->seen = false;
|
||||
|
||||
char *tmp = malloc(strlen(s) + 1);
|
||||
if (tmp != NULL)
|
||||
{
|
||||
strcpy(tmp, s);
|
||||
n->value = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle memory allocation failure
|
||||
free(n);
|
||||
return NULL;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* table_entry_kill() - Return the memory allocated to a table entry.
|
||||
* @e: The table entry to deallocate.
|
||||
*
|
||||
* Returns: Nothing.
|
||||
*/
|
||||
void node_kill(node *v)
|
||||
{
|
||||
//node *n = v; // Convert the pointer (useful if debugging the code)
|
||||
if (v == NULL) {
|
||||
return; // Nothing to free if v is NULL
|
||||
}
|
||||
|
||||
// free strings
|
||||
free((void*)v->value);
|
||||
|
||||
// All we need to do is to deallocate the struct.
|
||||
free(v);
|
||||
}
|
||||
|
||||
// =================== GRAPH STRUCTURE INTERFACE ======================
|
||||
|
||||
/**
|
||||
* 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 memory
|
||||
graph *g = calloc(1, sizeof(graph));
|
||||
|
||||
// Create the array for the entries
|
||||
g->entries = array_2d_create(0, max_nodes, 0, max_nodes + 1, NULL);
|
||||
g->nr_of_nodes = 0;
|
||||
g->nr_of_edges = 0;
|
||||
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)
|
||||
{
|
||||
// Returns true if nr_of_nodes is empty
|
||||
return g->nr_of_nodes == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Returns true if nr_of_edges is not empty
|
||||
return g->nr_of_edges != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Define variables and create a node entry with s for comparisons
|
||||
int index = 0;
|
||||
int count = 0;
|
||||
node *m = node_create(s);
|
||||
|
||||
// Check for duplicates among the already taken slots
|
||||
while (index < g->max_nodes && count < g->nr_of_nodes)
|
||||
{
|
||||
// Inspect the table entry
|
||||
node *n = array_2d_inspect_value(g->entries, index, 0);
|
||||
|
||||
// Check if the node already exists
|
||||
if (n != NULL && nodes_are_equal(n, m))
|
||||
{
|
||||
// If the node is a duplicate, exit the loop and skips the insertion loop
|
||||
node_kill(m);
|
||||
return g;
|
||||
}
|
||||
if (n != NULL)
|
||||
{
|
||||
// Update how many taken slots that have been checked
|
||||
count++;
|
||||
}
|
||||
// Continue with the next position.
|
||||
index++;
|
||||
}
|
||||
// If no duplicate is found, insert the node in the first available slot
|
||||
|
||||
while (index < g->max_nodes)
|
||||
{
|
||||
// Check for empty slot
|
||||
node *n = array_2d_inspect_value(g->entries, index, 0);
|
||||
if (n == NULL)
|
||||
{
|
||||
// Input node in the empty slot and update variables before exiting the loop
|
||||
m->position = index;
|
||||
m->seen = false;
|
||||
array_2d_set_value(g->entries, m, index, 0);
|
||||
g->nr_of_nodes++;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// Return the modified graph
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
int index = 0;
|
||||
int count = 0;
|
||||
node *m = node_create(s);
|
||||
|
||||
// Loop over the node list
|
||||
while (index < g->max_nodes && count < g->nr_of_nodes)
|
||||
{
|
||||
// Check if a node with value s exists and return it, if not continue to next node
|
||||
node *n = array_2d_inspect_value(g->entries, index, 0);
|
||||
if (n != NULL && nodes_are_equal(n, m))
|
||||
{
|
||||
// Deallocate comparison node
|
||||
node_kill(m);
|
||||
return n;
|
||||
}
|
||||
if (n != NULL)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// If no match is found, deallocate comparison node and return NULL
|
||||
node_kill(m);
|
||||
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)
|
||||
{
|
||||
// Check if node exists and return its seen-status
|
||||
node *m = graph_find_node(g, n->value);
|
||||
if (m != NULL)
|
||||
{
|
||||
return m->seen;
|
||||
}
|
||||
|
||||
// Return NULL if the node is not found
|
||||
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)
|
||||
{
|
||||
// Check if node exists and update its seen-status
|
||||
node *m = graph_find_node(g, n->value);
|
||||
if (m != NULL)
|
||||
{
|
||||
m->seen = seen;
|
||||
}
|
||||
|
||||
// Return the modified graph
|
||||
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)
|
||||
{
|
||||
int index = 0;
|
||||
int count = 0;
|
||||
|
||||
// Iterates over all nodes and sets the seen-status to FALSE
|
||||
while (index < g->max_nodes && count < g->nr_of_nodes)
|
||||
{
|
||||
node *n = array_2d_inspect_value(g->entries, index, 0);
|
||||
if (n != NULL)
|
||||
{
|
||||
n->seen = false;
|
||||
count++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
// Checks if both source and destination exists
|
||||
if (graph_find_node(g, n1->value) != NULL && graph_find_node(g, n2->value) != NULL)
|
||||
{
|
||||
// Inserts n2 into the edge list of n1 and updates the nr_of_edges
|
||||
array_2d_set_value(g->entries, n2, n1->position, n2->position + 1);
|
||||
g->nr_of_edges++;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_delete_node() - Remove a node from the graph.
|
||||
* @g: Graph to manipulate.
|
||||
* @n: Node to remove from the graph.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*
|
||||
* NOTE: Undefined if the node is not in the graph.
|
||||
*/
|
||||
graph *graph_delete_node(graph *g, node *n)
|
||||
{
|
||||
// Removes the node and all of its destinations
|
||||
for (int i = 0; i < g->max_nodes; i++)
|
||||
{
|
||||
array_2d_set_value(g->entries, NULL, n->position, 1);
|
||||
}
|
||||
|
||||
// Updatess the nr_of_nodes and returns the modified graph
|
||||
g->nr_of_nodes--;
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* graph_delete_edge() - Remove an edge from the graph.
|
||||
* @g: Graph to manipulate.
|
||||
* @n1: Source node (pointer) for the edge.
|
||||
* @n2: Destination node (pointer) for the edge.
|
||||
*
|
||||
* Returns: The modified graph.
|
||||
*
|
||||
* NOTE: Undefined if the edge is not in the graph.
|
||||
*/
|
||||
graph *graph_delete_edge(graph *g, node *n1, node *n2)
|
||||
{
|
||||
// Removes n2 from n1's destination list
|
||||
array_2d_set_value(g->entries, NULL, n1->position, n2->position + 1);
|
||||
g->nr_of_edges--;
|
||||
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)
|
||||
{
|
||||
// Creates the return list and gets its first position
|
||||
dlist *l = dlist_empty(NULL);
|
||||
dlist_pos pos = dlist_first(l);
|
||||
|
||||
if (n != NULL)
|
||||
{
|
||||
for (int i = 1; i <= g->max_nodes + 1; i++)
|
||||
{
|
||||
// If a destination exists add it to the list of neigbours and update the list position
|
||||
node *m = array_2d_inspect_value(g->entries, n->position, i);
|
||||
if (m != NULL)
|
||||
{
|
||||
dlist_insert(l, m, pos);
|
||||
pos = dlist_next(l, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of neigbours
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Iterate over the list of nodes and deallocate them
|
||||
for (int i = 0; i < g->max_nodes; i++)
|
||||
{
|
||||
|
||||
node *n = array_2d_inspect_value(g->entries, i, 0);
|
||||
node_kill(n);
|
||||
}
|
||||
|
||||
// free the array and the graph
|
||||
array_2d_kill(g->entries);
|
||||
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)
|
||||
{
|
||||
// Itirate over the list and print the value
|
||||
for (int i = 0; i < g->max_nodes; i++)
|
||||
{
|
||||
for (int j = 0; j < g->max_nodes + 1; j++)
|
||||
{
|
||||
node *n = array_2d_inspect_value(g->entries, i, j);
|
||||
|
||||
// Check if there is a value to print
|
||||
if (n != NULL && j == 0)
|
||||
{
|
||||
// Print the value
|
||||
printf("[%s] -> ", n->value);
|
||||
}
|
||||
else if (j == 0)
|
||||
{
|
||||
// Print no value
|
||||
printf("[###] -> ");
|
||||
}
|
||||
else if (n != NULL)
|
||||
{
|
||||
// Print the value
|
||||
printf("[%s] ", n->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print no value
|
||||
printf("[###] ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user