diff --git a/include/graph.h b/include/graph.h index d9ca7ea..8e45384 100644 --- a/include/graph.h +++ b/include/graph.h @@ -1,6 +1,7 @@ #ifndef GRAPH_H #define GRAPH_H +#include "arraylist.h" #include typedef struct Graph Graph; @@ -12,6 +13,7 @@ typedef enum { GRAPH_BAD_ALLOC, GRAPH_VERTEX_NOT_FOUND, GRAPH_NULL_ARG, + GRAPH_EMPTY, } GraphErr ; typedef enum { @@ -19,6 +21,11 @@ typedef enum { GRAPH_UNDIRECTED, } GraphType; +typedef struct { + ArrayList *distances; + ArrayList *prev; +} DijkstraResult; + Graph *graph_create(GraphType type); GraphErr graph_destroy(Graph **graph); @@ -32,5 +39,6 @@ GraphErr graph_connect_vertex( GraphErr graph_vertex_count(Graph *graph, size_t *out); GraphErr graph_get_vertex(Graph *graph, size_t index, Vertex *out); +GraphErr graph_dijkstra(Graph *graph, size_t source, DijkstraResult *result); #endif diff --git a/src/graph.c b/src/graph.c index 536485b..83d5ce0 100644 --- a/src/graph.c +++ b/src/graph.c @@ -1,10 +1,10 @@ #include "graph.h" #include "arraylist.h" #include +#include #include #include #include -#include struct Vertex { ArrayList *edges; @@ -122,3 +122,85 @@ GraphErr graph_get_vertex(Graph *graph, size_t index, Vertex *out) { return GRAPH_OK; } + +GraphErr graph_dijkstra(Graph *graph, size_t source, DijkstraResult *result) { + if (graph == NULL || result == NULL) { + return GRAPH_NULL_ARG; + } + + if (source >= arraylist_size(graph->vertices)) { + return GRAPH_VERTEX_NOT_FOUND; + } + + if (arraylist_size(graph->vertices) == 0) { + return GRAPH_EMPTY; + } + + size_t vertex_count = arraylist_size(graph->vertices); + + ArrayList *distances = arraylist_init(vertex_count, sizeof(size_t)); + ArrayList *visited = arraylist_init(vertex_count, sizeof(bool)); + ArrayList *prev = arraylist_init(vertex_count, sizeof(size_t)); + + for (size_t i = 0; i < vertex_count; i++) { + arraylist_push_back(distances, SIZE_MAX); + arraylist_push_back(visited, false); + arraylist_push_back(prev, SIZE_MAX); + } + + arraylist_set(distances, source, &(size_t){0}); + + for (size_t i = 0; i < vertex_count; i++) { + + size_t current = SIZE_MAX; + size_t min_dist = SIZE_MAX; + + for (size_t j = 0; j < vertex_count; j++) { + bool is_visited; + size_t dist; + + arraylist_get(visited, j, &is_visited); + arraylist_get(distances, j, &dist); + + if (!is_visited && dist < min_dist) { + min_dist = dist; + current = j; + } + } + + if (current == SIZE_MAX) { + break; + } + + arraylist_set(visited, current, &(bool){true}); + + Vertex vertex; + graph_get_vertex(graph, current, &vertex); + + for (size_t j = 0; j < arraylist_size(vertex.edges); j++) { + + Edge current_edge; + arraylist_get(vertex.edges, j, ¤t_edge); + + size_t current_dist; + arraylist_get(distances, current, ¤t_dist); + if (current_dist == SIZE_MAX) { + continue; + } + + size_t new_dist = current_dist + current_edge.weight; + + size_t to_dist; + arraylist_get(distances, current_edge.to, &to_dist); + if (new_dist < to_dist) { + arraylist_set(distances, current_edge.to, &new_dist); + arraylist_set(prev, current_edge.to, ¤t); + } + } + } + + arraylist_destroy(&visited); + *result = (DijkstraResult){.distances = distances, .prev = prev}; + + return GRAPH_OK; +}