Compare commits

..

10 Commits

6 changed files with 389 additions and 7 deletions

3
.gitignore vendored
View File

@@ -55,3 +55,6 @@ rules.ninja
# Git # Git
COMMIT_MESSAGE COMMIT_MESSAGE
docs
docs/images

View File

@@ -11,7 +11,38 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
option(GRAPH_BUILD_TESTS "Build arraylist tests" OFF) option(GRAPH_BUILD_TESTS "Build arraylist tests" OFF)
option(GRAPH_ENABLE_SANITIZERS "Enable sanitizers for tests" ON) option(GRAPH_ENABLE_SANITIZERS "Enable sanitizers for tests" ON)
include(cmake/CPM.cmake) # --------------------------------------------------
# CPM.cmake bootstrap
# --------------------------------------------------
set(CPM_DOWNLOAD_VERSION 0.40.2)
set(CPM_DOWNLOAD_LOCATION
"${CMAKE_BINARY_DIR}/cmake/CPM.cmake"
)
if(NOT EXISTS ${CPM_DOWNLOAD_LOCATION})
message(STATUS "Downloading CPM.cmake...")
file(
DOWNLOAD
"https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake"
"${CPM_DOWNLOAD_LOCATION}"
STATUS download_status
)
list(GET download_status 0 status_code)
if(NOT status_code EQUAL 0)
message(FATAL_ERROR
"Failed to download CPM.cmake"
)
endif()
endif()
include("${CPM_DOWNLOAD_LOCATION}")
CPMAddPackage( CPMAddPackage(
NAME arraylist NAME arraylist

View File

@@ -1,6 +1,7 @@
#ifndef GRAPH_H #ifndef GRAPH_H
#define GRAPH_H #define GRAPH_H
#include "arraylist.h"
#include <stdlib.h> #include <stdlib.h>
typedef struct Graph Graph; typedef struct Graph Graph;
@@ -9,6 +10,10 @@ typedef struct Edge Edge;
typedef enum { typedef enum {
GRAPH_OK, GRAPH_OK,
GRAPH_BAD_ALLOC,
GRAPH_VERTEX_NOT_FOUND,
GRAPH_NULL_ARG,
GRAPH_EMPTY,
} GraphErr ; } GraphErr ;
typedef enum { typedef enum {
@@ -16,5 +21,27 @@ typedef enum {
GRAPH_UNDIRECTED, GRAPH_UNDIRECTED,
} GraphType; } GraphType;
typedef struct {
ArrayList *distances;
ArrayList *prev;
} DijkstraResult;
Graph *graph_create(GraphType type);
GraphErr graph_destroy(Graph **graph);
GraphErr graph_add_vertex(Graph *graph);
GraphErr graph_connect_vertex(
Graph *graph,
size_t node1,
size_t node2,
size_t weight);
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);
void graph_print(Graph *graph);
void dijkstra_print_result(DijkstraResult *result);
#endif #endif

View File

@@ -1,22 +1,304 @@
#include "graph.h" #include "graph.h"
#include "arraylist.h" #include "arraylist.h"
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
struct Vertex { struct Vertex {
void *data;
ArrayList *edges; ArrayList *edges;
}; };
struct Edge { struct Edge {
size_t *to; size_t to;
intmax_t weight; size_t weight;
}; };
struct Graph { struct Graph {
ArrayList *vertices; ArrayList *vertices;
GraphType type; GraphType type;
int (*cmp)(const void*, const void*);
void (*free_data)(void*);
}; };
Graph *graph_create(GraphType type) {
Graph *graph = malloc(sizeof(Graph));
if (graph == NULL) {
return NULL;
}
graph->type = type;
arraylist_init(&graph->vertices, 64, sizeof(Vertex));
if (graph->vertices == NULL) {
free(graph);
return NULL;
}
return graph;
}
GraphErr graph_destroy(Graph **graph) {
if (graph == NULL || *graph == NULL) {
return GRAPH_NULL_ARG;
}
size_t vertex_count = arraylist_size((*graph)->vertices);
for (size_t i = 0; i < vertex_count; i++) {
Vertex vertex;
arraylist_get((*graph)->vertices, i, &vertex);
arraylist_destroy(&vertex.edges);
}
arraylist_destroy(&(*graph)->vertices);
free(*graph);
*graph = NULL;
return GRAPH_OK;
}
GraphErr graph_add_vertex(Graph *graph) {
if (graph == NULL) {
return GRAPH_NULL_ARG;
}
Vertex new_vertex = {.edges = NULL };
arraylist_init(&new_vertex.edges, 16, sizeof(Edge));
arraylist_push_back(graph->vertices, &new_vertex);
return GRAPH_OK;
}
GraphErr graph_connect_vertex(
Graph *graph,
size_t node1,
size_t node2,
size_t weight) {
if (graph == NULL) {
return GRAPH_NULL_ARG;
}
size_t vertex_count = arraylist_size(graph->vertices);
if (node1 >= vertex_count || node2 >= vertex_count) {
return GRAPH_VERTEX_NOT_FOUND;
}
Edge new_edge = {.to = node2, .weight = weight};
Vertex vertex1;
Vertex vertex2;
arraylist_get(graph->vertices, node1, &vertex1);
arraylist_get(graph->vertices, node2, &vertex2);
arraylist_push_back(vertex1.edges, &new_edge);
if (graph->type == GRAPH_UNDIRECTED) {
Edge inverse_edge = {.to = node1, .weight = weight};
arraylist_push_back(vertex2.edges, &inverse_edge);
}
return GRAPH_OK;
}
GraphErr graph_vertex_count(Graph *graph, size_t *out) {
if (graph == NULL) {
return GRAPH_NULL_ARG;
}
*out = arraylist_size(graph->vertices);
return GRAPH_OK;
}
GraphErr graph_get_vertex(Graph *graph, size_t index, Vertex *out) {
if (graph == NULL || out == NULL) {
return GRAPH_NULL_ARG;
}
if (index >= arraylist_size(graph->vertices)) {
return GRAPH_VERTEX_NOT_FOUND;
}
arraylist_get(graph->vertices, index, 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(&distances, vertex_count, sizeof(size_t));
ArrayList *visited;
arraylist_init(&visited, vertex_count, sizeof(bool));
ArrayList *prev;
arraylist_init(&prev, vertex_count, sizeof(size_t));
for (size_t i = 0; i < vertex_count; i++) {
arraylist_push_back(distances, &(size_t){SIZE_MAX});
arraylist_push_back(visited, false);
arraylist_push_back(prev, &(size_t){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, &current_edge);
size_t current_dist;
arraylist_get(distances, current, &current_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, &current);
}
}
}
arraylist_destroy(&visited);
*result = (DijkstraResult){.distances = distances, .prev = prev};
return GRAPH_OK;
}
void graph_print(Graph *graph) {
if (graph == NULL) {
return;
}
size_t vertex_count = arraylist_size(graph->vertices);
printf("Graph {\n");
for (size_t i = 0; i < vertex_count; i++) {
Vertex vertex;
arraylist_get(graph->vertices, i, &vertex);
printf(" [%zu] -> ", i);
size_t edge_count = arraylist_size(vertex.edges);
for (size_t j = 0; j < edge_count; j++) {
Edge edge;
arraylist_get(vertex.edges, j, &edge);
printf("(%zu, w=%zu)", edge.to, edge.weight);
if (j + 1 < edge_count) {
printf(" -> ");
}
}
printf("\n");
}
printf("}\n");
}
void dijkstra_print_result(DijkstraResult *result) {
if (result == NULL) {
return;
}
size_t count = arraylist_size(result->distances);
printf("Dijkstra Result {\n");
for (size_t i = 0; i < count; i++) {
size_t dist;
arraylist_get(result->distances, i, &dist);
printf(" [%zu] ", i);
if (dist == SIZE_MAX) {
printf("dist=INF\n");
continue;
}
printf("dist=%zu ", dist);
size_t path[count];
size_t path_len = 0;
size_t current = i;
while (current != SIZE_MAX) {
path[path_len++] = current;
size_t next;
arraylist_get(result->prev, current, &next);
current = next;
}
printf("path= ");
for (size_t j = path_len; j > 0; j--) {
printf("%zu", path[j - 1]);
if (j > 1) {
printf(" -> ");
}
}
printf("\n");
}
printf("}\n");
}

View File

@@ -1,5 +1,39 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "graph.h"
int main(void) { int main(void) {
Graph *graph = graph_create(GRAPH_UNDIRECTED);
graph_add_vertex(graph); // 0
graph_add_vertex(graph); // 1
graph_add_vertex(graph); // 2
graph_add_vertex(graph); // 3
graph_add_vertex(graph); // 4
graph_add_vertex(graph); // 5
graph_add_vertex(graph); // 6
graph_add_vertex(graph); // 7
graph_connect_vertex(graph, 0, 1, 5);
graph_connect_vertex(graph, 0, 2, 2);
graph_connect_vertex(graph, 1, 2, 1);
graph_connect_vertex(graph, 1, 3, 3);
graph_connect_vertex(graph, 1, 4, 12);
graph_connect_vertex(graph, 2, 3, 7);
graph_connect_vertex(graph, 2, 5, 10);
graph_connect_vertex(graph, 3, 4, 2);
graph_connect_vertex(graph, 3, 5, 6);
graph_connect_vertex(graph, 4, 6, 1);
graph_connect_vertex(graph, 5, 6, 3);
graph_connect_vertex(graph, 5, 7, 5);
graph_connect_vertex(graph, 6, 7, 2);
DijkstraResult result;
graph_dijkstra(graph, 0, &result);
puts("Algoritmo de dijsktra");
graph_print(graph);
dijkstra_print_result(&result);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,5 @@
#include <stdlib.h>
int main(void) {
return EXIT_SUCCESS;
}