Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/graph/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ INCLUDE := -I../ -L../list/single -L../hash-table -L../set -L../queue -L../stac

# targets to compile
TEST_TARGET = test
TARGETS = graph.o bfs.o dfs.o acyclical.o tarjan.o dijkstra.o kruskal.o
TARGETS = graph.o bfs.o dfs.o acyclical.o tarjan.o dijkstra.o kruskal.o prim.o
LIBRARY_OBJS = $(TARGETS)

TEST_BINARY = $(TEST_TARGET).$(EXTENSION)
Expand Down
38 changes: 38 additions & 0 deletions src/graph/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,38 @@ List* graph_edges_ordered(Graph *g) {
}

return edges_ordered;
}


List* graph_remove_duplicated_edges(List* edges) {
List *node = edges;
while (node != NULL) {
int u = node->key;
int v = node->data;
edges = list_remove_by_key_data(edges, v, u);
node = node->next;
}
return edges;
}

int graph_edges_sum(Graph *g) {
int s = 0;
List *edges = graph_edges(g);

if (!g->directed) {
edges = graph_remove_duplicated_edges(edges);
}

Iterator *it = list_iterator(edges);
while (!iterator_done(it)) {
List *node = (List*) iterator_next(it);
int u = node->key;
int v = node->data;
s += graph_get_edge_weight(g, u, v);
}
list_free(edges);
iterator_free(it);
return s;
}

size_t graph_size(Graph *g) {
Expand Down Expand Up @@ -232,6 +263,12 @@ bool graph_has_edge(Graph *g, int u, int v) {
return set_contains(set_u, v);
}

bool graph_has_node(Graph *g, int u) {
bool exists;
hash_table_gen_get(g->adj, u, &exists);
return exists;
}

Set* graph_get_neighbors(Graph *g, int node) {
bool exists;
Set *neighbors = (Set*) hash_table_gen_get(g->adj, node, &exists);
Expand All @@ -257,6 +294,7 @@ void graph_print(Graph *g) {
Iterator *it = graph_nodes_iterator(g);
while(!iterator_done(it)) {
int u = *(int*)iterator_next(it);
printf("%d: ", u);
Set *neighbors = (Set*) hash_table_gen_get(g->adj, u, NULL);
if (g->tarjan) {
Iterator *neighbors_it = set_iterator_items(neighbors);
Expand Down
27 changes: 26 additions & 1 deletion src/graph/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ void graph_remove_node(Graph *g, int node);
*/
bool graph_has_edge(Graph *g, int u, int v);

/**
* @brief Checks if a node exists in the graph.
* @param g The graph.
* @param u The node.
* @return True if the node exists, false otherwise.
* @ingroup DataStructureMethods
*/
bool graph_has_node(Graph *g, int u);

/**
* @brief Gets the neighbors of a node.
* @param g The graph.
Expand Down Expand Up @@ -215,6 +224,13 @@ List* graph_edges(Graph *g);
*/
List* graph_edges_ordered(Graph *g);

/**
* @brief Sum of the edge weights. If undirected, calculate (u, v) == (v, u) only once.
* @param g The graph to traverse.
* @ingroup DataStructureMethods
*/
int graph_edges_sum(Graph *g);

/**
* @brief Get the maximum node id on the graph.
* @return maximum node id on the graph.
Expand Down Expand Up @@ -274,13 +290,22 @@ List* graph_topological_sort(Graph *g);
Graph* graph_dijkstra(Graph* g, int source);

/**
* @brief Run kruskal algorithm to get the minimum-span tree.
* @brief Run Kruskal algorithm to get the minimum-span tree.
* @param g The graph to traverse.
* @return a new graph with the minimum span tree.
* @ingroup DataStructureMethods
*/
Graph* graph_kruskal(Graph* g);

/**
* @brief Run Prim algorithm to get the minimum-span tree.
* @param g The graph to traverse.
* @param start Initial node to start.
* @return a new graph with the minimum span tree.
* @ingroup DataStructureMethods
*/
Graph* graph_prim(Graph* g, int start);

/**
* @brief Run dijkstra algorithm and calculate the minimum distance.
* @param g The graph to traverse.
Expand Down
2 changes: 1 addition & 1 deletion src/graph/kruskal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "../set/set-disjoint.h"

Graph* graph_kruskal(Graph *g) {
Graph *g_kruskal = graph_create();
Graph *g_kruskal = graph_undirected_create();
DisjointSet *components = set_disjoint_create(graph_max_node_id(g) + 1);
List *edges = graph_edges_ordered(g);
Iterator *it = list_iterator(edges);
Expand Down
46 changes: 46 additions & 0 deletions src/graph/prim.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "graph.h"
#include "../utils/pair_hash.h"
#include "../pqueue/pqueue.h"

void update_heap(Graph* g, PQueue* pq, Set* visited, int start) {
Set* neighbors = graph_get_neighbors(g, start);
Iterator *it = set_iterator_items(neighbors);
while (!iterator_done(it)) {
List *neighbor_weight = (List*) iterator_next(it);
if (!set_contains(visited, neighbor_weight->key)) {
int k = pair_hash(start, neighbor_weight->key);
int w = neighbor_weight->data;
pqueue_insert(pq, k, w);
}
}
set_free(neighbors);
iterator_free(it);
}

// WARNING: this implementation only return the Minimum Spanning Tree
// of conected component from <start> node. If some node is
// unreachable from <start> will be not included in the final tree.
Graph* graph_prim(Graph *g, int start) {
Graph* g_prim = graph_undirected_create();
Set* visited = set_create();
PQueue *pq = pqueue_create(MIN_PQUEUE);
update_heap(g, pq, visited, start);
set_add(visited, start);

while (!pqueue_is_empty(pq)) {
PQueueNode node = pqueue_extract(pq);
int u = unpair_hash_x(node.key);
int v = unpair_hash_y(node.key);
int w = node.value;
if (set_contains(visited, v)) {
continue;
}
graph_add_edge_with_weight(g_prim, u, v, w);
set_add(visited, v);
update_heap(g, pq, visited, v);
}
pqueue_free(pq);
set_free(visited);

return g_prim;
}
2 changes: 1 addition & 1 deletion src/graph/tarjan.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct TarjanContext {
};

void free_tarjan_context(struct TarjanContext *tc) {
// keep on memor: g_tarjan + componentes
// keep on memory: g_tarjan + components
free(tc->exploration);
free(tc->complete);
stack_free(tc->path);
Expand Down
56 changes: 51 additions & 5 deletions src/graph/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void test_graph_edges_ordered() {
graph_add_edge_with_weight(g, 2, 3, 10);
graph_add_edge_with_weight(g, 1, 2, 7);
graph_add_edge_with_weight(g, 1, 3, 9);
printf(":: graph");
printf(":: graph\n");
graph_print(g);


Expand Down Expand Up @@ -389,9 +389,11 @@ void test_graph_dijkstra(bool extra_tests) {
graph_free(dijkstra_result);
}

void test_graph_kruskal() {
void test_graph_kruskal(bool extra_tests) {
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
puts("== Graph kruskal test");
Graph *g = graph_create();
Graph *g = graph_undirected_create();
graph_add_edge_with_weight(g, 1, 2, 10);
graph_add_edge_with_weight(g, 1, 3, 20);
graph_add_edge_with_weight(g, 2, 3, 5);
Expand All @@ -402,14 +404,57 @@ void test_graph_kruskal() {
printf(":: input graph\n");
graph_print(g);

printf(":: kruskal tree\n");
printf(":: kruskal minimum spanning tree\n");
Graph *g_kruskal = graph_kruskal(g);
graph_print(g_kruskal);

if (extra_tests) {
graph_export_to_dot(g, "test_graph_kruskal_input.dot");
printf("saved input: %s/test_graph_kruskal_input.dot\n", cwd);
graph_export_to_dot(g_kruskal, "test_graph_kruskal_output.dot");
printf("saved output: %s/test_graph_kruskal_output.dot\n", cwd);
}

int s = graph_edges_sum(g_kruskal);
printf("Cost sum: %d\n", s);
assert(s == 31);
graph_free(g);
graph_free(g_kruskal);
}

void test_graph_prim(bool extra_tests) {
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
puts("== Graph prim test");
Graph *g = graph_undirected_create();
graph_add_edge_with_weight(g, 1, 2, 10);
graph_add_edge_with_weight(g, 1, 3, 20);
graph_add_edge_with_weight(g, 2, 3, 5);
graph_add_edge_with_weight(g, 3, 4, 30);
graph_add_edge_with_weight(g, 4, 1, 9);
graph_add_edge_with_weight(g, 5, 1, 7);

printf(":: input graph\n");
graph_print(g);

printf(":: prim minimum spanning tree\n");
Graph *g_prim = graph_prim(g, 5);
graph_print(g_prim);

if (extra_tests) {
graph_export_to_dot(g, "test_graph_prim_input.dot");
printf("saved input: %s/test_graph_prim_input.dot\n", cwd);
graph_export_to_dot(g_prim, "test_graph_prim_output.dot");
printf("saved output: %s/test_graph_prim_output.dot\n", cwd);
}

int s = graph_edges_sum(g_prim);
printf("Cost sum: %d\n", s);
assert(s == 31);
graph_free(g);
graph_free(g_prim);
}


bool should_run_extra_tests(int argc, char *argv[]) {
// Iterate through the command-line arguments starting from argv[1]
Expand All @@ -434,7 +479,8 @@ int main(int argc, char *argv[]) {
test_graph_topological_sort();
test_graph_dijkstra(extra_tests);
test_graph_edges_ordered();
test_graph_kruskal();
test_graph_kruskal(extra_tests);
test_graph_prim(extra_tests);
if (should_run_extra_tests(argc, argv)) {
test_graph_export();
}
Expand Down
13 changes: 13 additions & 0 deletions src/list/single/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,19 @@ List* list_remove(List *l, int data) {
return l;
}

List* list_remove_by_key_data(List *l, int key, int data) {
if (!list_empty(l)) {
if (l->key == key && l->data == data) {
List* next = l->next;
free(l);
l = next;
} else {
l->next = list_remove_by_key_data(l->next, key, data);
}
}
return l;
}

List* list_remove_by_key(List *l, int key){
if (!list_empty(l)) {
if (l->key == key) {
Expand Down
11 changes: 11 additions & 0 deletions src/list/single/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ List* list_remove(List *l, int data);
*/
List* list_remove_by_key(List *l, int key);


/**
* @brief Remove specific element from List by a key equal data
* @param l List to remove with \p key
* @param key integer value to remove
* @param data integer value to remove
* @return new list without the node which contains \p key and \p data
* @ingroup DataStructureMethods
*/
List* list_remove_by_key_data(List *l, int key, int data);

/**
* @brief Free memory of List and its nodes
* @ingroup DataStructureMethods
Expand Down
2 changes: 1 addition & 1 deletion src/pqueue/pqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ void min_heapify(PQueue *pq, int i) {

PQueue* pqueue_create(PQueueType type) {
PQueue* pq = (PQueue*) malloc(sizeof(PQueue));
pq->index = hash_table_create(PQUEUE_SIZE * 10);
if (pq == NULL) {
perror("Failed to allocate memory for PQueue");
exit(EXIT_FAILURE);
}
pq->index = hash_table_create(PQUEUE_SIZE * 10);
pq->heap = (PQueueNode*) malloc(PQUEUE_SIZE * sizeof(PQueueNode));
if (pq->heap == NULL) {
perror("Failed to allocate memory for PQueue heap");
Expand Down
31 changes: 31 additions & 0 deletions src/utils/pair_hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <math.h>

/* @brief Pair function of Szudzik (2006).
* @details Useful to encapsulate two integers as a unique reversible integer hash.
* @return hashed integer.
* @see https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function
*/
static inline int pair_hash(int x, int y) {
Comment thread
ryukinix marked this conversation as resolved.
if (x < y) {
return y * y + x;
}
return x * x + x + y;
}

static inline int unpair_hash_x(int z) {
int z_sqrt = floor(sqrt(z));
int z_rest = z - z_sqrt * z_sqrt;
if (z_rest < z_sqrt) {
return z_rest;
}
return z_rest;
}

static inline int unpair_hash_y(int z) {
int z_sqrt = floor(sqrt(z));
int z_rest = z - z_sqrt * z_sqrt;
if (z_rest < z_sqrt) {
return z_sqrt;
}
return z_rest - z_sqrt;
}