Compare commits
10 Commits
0241829777
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| eaaa09aaee | |||
| ad1824246c | |||
| 1347adfcaa | |||
| 19d1c2d984 | |||
| a20e77c09a | |||
| 60b9830db7 | |||
| 36fa8aa09b | |||
| d75adf8510 | |||
| 8b6ec8ce2e | |||
| 94cfb10960 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -55,3 +55,6 @@ rules.ninja
|
||||
|
||||
# Git
|
||||
COMMIT_MESSAGE
|
||||
|
||||
docs
|
||||
docs/images
|
||||
|
||||
@@ -11,7 +11,38 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
option(GRAPH_BUILD_TESTS "Build arraylist tests" OFF)
|
||||
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(
|
||||
NAME arraylist
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef GRAPH_H
|
||||
#define GRAPH_H
|
||||
|
||||
#include "arraylist.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct Graph Graph;
|
||||
@@ -9,6 +10,10 @@ typedef struct Edge Edge;
|
||||
|
||||
typedef enum {
|
||||
GRAPH_OK,
|
||||
GRAPH_BAD_ALLOC,
|
||||
GRAPH_VERTEX_NOT_FOUND,
|
||||
GRAPH_NULL_ARG,
|
||||
GRAPH_EMPTY,
|
||||
} GraphErr ;
|
||||
|
||||
typedef enum {
|
||||
@@ -16,5 +21,27 @@ typedef enum {
|
||||
GRAPH_UNDIRECTED,
|
||||
} 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
|
||||
|
||||
294
src/graph.c
294
src/graph.c
@@ -1,22 +1,304 @@
|
||||
#include "graph.h"
|
||||
#include "arraylist.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct Vertex {
|
||||
void *data;
|
||||
ArrayList *edges;
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
size_t *to;
|
||||
intmax_t weight;
|
||||
size_t to;
|
||||
size_t weight;
|
||||
};
|
||||
|
||||
struct Graph {
|
||||
ArrayList *vertices;
|
||||
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, ¤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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
34
src/main.c
34
src/main.c
@@ -1,5 +1,39 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "graph.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user