Initial Commit

This commit is contained in:
Marc
2025-09-13 14:40:16 +02:00
commit ded01301c2
383 changed files with 71046 additions and 0 deletions

484
OU4/graph.c Normal file
View 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");
}
}