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
TARGETS = graph.o bfs.o dfs.o acyclical.o tarjan.o dijkstra.o kruskal.o
LIBRARY_OBJS = $(TARGETS)

TEST_BINARY = $(TEST_TARGET).$(EXTENSION)
Expand Down
69 changes: 63 additions & 6 deletions src/graph/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,63 @@ List* graph_edges(Graph *g) {
return edges;
}

int graph_edges_count(Graph *g) {
Iterator *nodes = graph_nodes_iterator(g);
int n_edges = 0;
while (!iterator_done(nodes)) {
int node = *(int*) iterator_next(nodes);
Set* neighbors = graph_get_neighbors(g, node);
n_edges += set_size(neighbors);
set_free(neighbors);
}
iterator_free(nodes);
return n_edges;
}

// compare edges in descending order
int _compare_edge_weight(const void *a, const void *b) {
int x = *((const int*)a + 2);
int y = *((const int*)b + 2);
if (x < y) {
return 1;
} else if (x > y) {
return -1;
} else {
return 0;
}
}

// return a list of edges ordered in ascending order
List* graph_edges_ordered(Graph *g) {
int edges_count = graph_edges_count(g);
int edges_by_weight[edges_count][3];
List *edges = graph_edges(g);
Iterator *it = list_iterator(edges);
int rows = 0;
while (!iterator_done(it)) {
List *edge = (List*) iterator_next(it);
int u = edge->key;
int v = edge->data;
int w = graph_get_edge_weight(g, u, v);
edges_by_weight[rows][0] = u;
edges_by_weight[rows][1] = v;
edges_by_weight[rows][2] = w;
rows++;
}
iterator_free(it);
list_free(edges);

qsort(edges_by_weight, edges_count, sizeof(int) * 3, _compare_edge_weight);
List *edges_ordered = list_create();
for (int i = 0; i < edges_count; i++) {
int u = edges_by_weight[i][0];
int v = edges_by_weight[i][1];
edges_ordered = list_insert_with_key(edges_ordered, u, v);
}

return edges_ordered;

}

size_t graph_size(Graph *g) {
return hash_table_gen_size(g->adj);
Expand Down Expand Up @@ -202,17 +259,17 @@ void graph_print(Graph *g) {
int u = *(int*)iterator_next(it);
Set *neighbors = (Set*) hash_table_gen_get(g->adj, u, NULL);
if (g->tarjan) {
Iterator *it = set_iterator_items(neighbors);
Iterator *neighbors_it = set_iterator_items(neighbors);
printf("{");
while (!iterator_done(it)) {
List *list = (List*) iterator_next(it);
while (!iterator_done(neighbors_it)) {
List *list = (List*) iterator_next(neighbors_it);
printf("%d:%s", list->key, graph_edge_type_name((EdgeType)list->data));
if (!iterator_done(it)) {
if (!iterator_done(neighbors_it)) {
printf(", ");
}
}
printf("}\n");
iterator_free(it);
iterator_free(neighbors_it);
} else if (g->weighted) {
set_print_items(neighbors);
} else {
Expand All @@ -231,8 +288,8 @@ void graph_free(Graph *g) {
void graph_export_to_dot(Graph *g, const char* filename) {
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
return;
fprintf(stderr, "Could not open file %s for writing\n", filename);
return;
}

fprintf(fp, "%s G {\n", g->directed ? "digraph" : "graph");
Expand Down
23 changes: 23 additions & 0 deletions src/graph/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ Iterator* graph_nodes_iterator(Graph *g);
*/
List* graph_edges(Graph *g);

/**
* @brief List with edges of the graph with (key,data) ordered ascending.
* @param g The graph to traverse.
* @ingroup DataStructureMethods
*/
List* graph_edges_ordered(Graph *g);

/**
* @brief Get the maximum node id on the graph.
* @return maximum node id on the graph.
Expand Down Expand Up @@ -239,6 +246,14 @@ bool graph_is_dag(Graph *g);
*/
Graph* graph_tarjan(Graph *g);

/**
* @brief Create a array of strong components using tarjan algorithm.
* @param g The graph to traverse.
* @return array of componentes indexed by node id.
* @ingroup DataStructureMethods
*/
int* graph_strong_components(Graph *g);

/**
* This method is defined in acyclical.c because it inherits part of the acyclical code.
*
Expand All @@ -258,6 +273,14 @@ List* graph_topological_sort(Graph *g);
*/
Graph* graph_dijkstra(Graph* g, int source);

/**
* @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 dijkstra algorithm and calculate the minimum distance.
* @param g The graph to traverse.
Expand Down
24 changes: 24 additions & 0 deletions src/graph/kruskal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "graph.h"
#include "../set/set-disjoint.h"

Graph* graph_kruskal(Graph *g) {
Graph *g_kruskal = graph_create();
DisjointSet *components = set_disjoint_create(graph_max_node_id(g) + 1);
List *edges = graph_edges_ordered(g);
Iterator *it = list_iterator(edges);

while (!iterator_done(it)) {
List *edge = (List*) iterator_next(it);
int u = edge->key;
int v = edge->data;
if (set_disjoint_find(components, u) != set_disjoint_find(components, v)) {
graph_add_edge_with_weight(g_kruskal, u, v, graph_get_edge_weight(g, u, v));
set_disjoint_union(components, u, v);
}
}

set_disjoint_free(components);
iterator_free(it);
list_free(edges);
return g_kruskal;
}
88 changes: 69 additions & 19 deletions src/graph/tarjan.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,22 @@

struct TarjanContext {
Graph* g_tarjan;
int *components;
Stack* path; // for strong connected components
int counter_exploration;
int counter_complete;
int *exploration;
int *complete;
};

void free_tarjan_context(struct TarjanContext *tc) {
// keep on memor: g_tarjan + componentes
free(tc->exploration);
free(tc->complete);
stack_free(tc->path);
free(tc);
}

EdgeType tarjan_classify_edge(struct TarjanContext *tc, int parent, int u) {
if (tc->exploration[u] == 0) {
return TREE;
Expand All @@ -21,13 +31,28 @@ EdgeType tarjan_classify_edge(struct TarjanContext *tc, int parent, int u) {
}
}

int update_components(struct TarjanContext *tc, EdgeType edge_type, int u, int v) {
if (edge_type == TREE) {
int tcu = tc->components[u];
int tcv = tc->components[v];
return tcu < tcv? tcu: tcv;
} else if (stack_has(tc->path, v)) {
int tcu = tc->components[u];
int exv = tc->exploration[v];
return tcu < exv? tcu: exv;
}
return tc->components[u];
}


static void graph_dfst(
Graph *g,
int node,
struct TarjanContext *tc
) {
tc->exploration[node] = ++tc->counter_exploration;

tc->components[node] = tc->exploration[node];
stack_push(tc->path, node);
Set* neighbors_set = graph_get_neighbors(g, node);
Iterator* set_it = set_iterator(neighbors_set);

Expand All @@ -41,43 +66,68 @@ static void graph_dfst(
if (edge_type == TREE) {
graph_dfst(g, neighbor, tc);
}

tc->components[node] = update_components(tc, edge_type, node, neighbor);
}

// pop elements for components visited in a cycle
if (tc->components[node] == tc->exploration[node]) {
while (stack_pop(tc->path) != node);
}
set_free(neighbors_set);
iterator_free(set_it);

tc->complete[node] = ++tc->counter_complete;
}


Graph* graph_tarjan(Graph *g) {
struct TarjanContext tc;
struct TarjanContext* graph_tarjan_explore(Graph *g) {
struct TarjanContext *tc = (struct TarjanContext*) malloc(sizeof(struct TarjanContext));
int max_node_id = graph_max_node_id(g);
int *exploration = (int*) malloc(sizeof(int) * (max_node_id + 1));
for (int i = 0; i <= max_node_id; i++) {
int n = max_node_id + 1;
int *exploration = (int*) malloc(n * sizeof(int));
int *complete = (int*) malloc(n * sizeof(int));
int *components= (int*) malloc(n * sizeof(int));

// initialize arrays
for (int i = 0; i < n; i++) {
exploration[i] = 0;
}
int *complete = (int*) malloc(sizeof(int) * (max_node_id + 1));
for (int i = 0; i <= max_node_id; i++) {
complete[i] = 0;
components[i] = -1;
}

tc.g_tarjan = graph_tarjan_create(graph_is_directed(g));
tc.counter_complete = 0;
tc.counter_exploration = 0;
tc.exploration = exploration;
tc.complete = complete;
tc->g_tarjan = graph_tarjan_create(graph_is_directed(g));
tc->counter_complete = 0;
tc->counter_exploration = 0;
tc->exploration = exploration;
tc->complete = complete;
tc->components = components;
tc->path = stack_create();

// dfs over each node
Iterator *nodes = graph_nodes_iterator(g);
while (!iterator_done(nodes)) {
int node = *(int*) iterator_next(nodes);
if (tc.exploration[node] == 0) {
graph_dfst(g, node, &tc);
if (tc->exploration[node] == 0) {
graph_dfst(g, node, tc);
}

}
iterator_free(nodes);
free(exploration);
free(complete);
return tc.g_tarjan;
return tc;
}

Graph* graph_tarjan(Graph *g) {
struct TarjanContext *tc= graph_tarjan_explore(g);
Graph* g_tarjan = tc->g_tarjan;
free(tc->components);
free_tarjan_context(tc);
return g_tarjan;
}

int* graph_strong_components(Graph *g) {
struct TarjanContext *tc= graph_tarjan_explore(g);
int* components = tc->components;
graph_free(tc->g_tarjan);
free_tarjan_context(tc);
return components;
}
Loading