Compare commits
10 Commits
0241829777
...
eaaa09aaee
| 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
|
# Git
|
||||||
COMMIT_MESSAGE
|
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_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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
294
src/graph.c
294
src/graph.c
@@ -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, ¤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 <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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user