86 lines
2.9 KiB
C
86 lines
2.9 KiB
C
#include <c_DepthFirstDirectedPaths.h>
|
|||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
|
||
|
|
/* Private recursive engine helper */
|
||
|
|
static void c_DepthFirstDirectedPaths_Traverse(c_DepthFirstDirectedPaths_t* self, const c_Digraph_t* graph, c_size_t v) {
|
||
|
|
self->marked[v] = C_TRUE;
|
||
|
|
|
||
|
|
c_AdjList_t* adj = &graph->adj_list[v];
|
||
|
|
c_size_t size = (c_size_t)c_UIntArray_GetSize(adj);
|
||
|
|
|
||
|
|
for (c_size_t i = 0; i < size; ++i) {
|
||
|
|
c_uint_t target_value = 0;
|
||
|
|
/* Using the safe signature to extract the neighbor vertex index */
|
||
|
|
c_err_t err = c_UIntArray_Get(adj, i, &target_value);
|
||
|
|
|
||
|
|
if (err == C_SUCCESS) {
|
||
|
|
c_size_t w = (c_size_t)target_value;
|
||
|
|
if (!self->marked[w]) {
|
||
|
|
self->edge_to[w] = v; /* Record parent routing step link */
|
||
|
|
c_DepthFirstDirectedPaths_Traverse(self, graph, w);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
c_err_t c_DepthFirstDirectedPaths_Init(c_DepthFirstDirectedPaths_t* self, const c_Digraph_t* graph, c_size_t s, c_Allocator_t* allocator) {
|
||
|
|
if (!self || !graph || s >= graph->V) return C_ERR_PARAM;
|
||
|
|
|
||
|
|
self->allocator = allocator ? *allocator : c_DefaultAllocator;
|
||
|
|
self->s = s;
|
||
|
|
|
||
|
|
self->marked = (c_bool_t*)c_Allocator_Calloc(&self->allocator, graph->V, sizeof(c_bool_t));
|
||
|
|
if (!self->marked) return C_ERR_NOMEM;
|
||
|
|
|
||
|
|
self->edge_to = (c_size_t*)c_Allocator_Calloc(&self->allocator, graph->V, sizeof(c_size_t));
|
||
|
|
if (!self->edge_to) {
|
||
|
|
c_Allocator_Free(&self->allocator, self->marked);
|
||
|
|
self->marked = NULL;
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_DepthFirstDirectedPaths_Traverse(self, graph, s);
|
||
|
|
return C_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_DepthFirstDirectedPaths_Destroy(c_DepthFirstDirectedPaths_t* self) {
|
||
|
|
if (!self) return;
|
||
|
|
|
||
|
|
if (self->marked) {
|
||
|
|
c_Allocator_Free(&self->allocator, self->marked);
|
||
|
|
self->marked = NULL;
|
||
|
|
}
|
||
|
|
if (self->edge_to) {
|
||
|
|
c_Allocator_Free(&self->allocator, self->edge_to);
|
||
|
|
self->edge_to = NULL;
|
||
|
|
}
|
||
|
|
self->s = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_err_t c_DepthFirstDirectedPaths_PathTo(c_DepthFirstDirectedPaths_t* self, c_size_t v, c_size_t total_V, c_VertexIdList_t* out_path) {
|
||
|
|
if (!self || !out_path || v >= total_V) return C_ERR_PARAM;
|
||
|
|
if (!c_DepthFirstDirectedPaths_HasPathTo(self, v, total_V)) return C_ERR_FAIL;
|
||
|
|
|
||
|
|
c_size_t* reverse_stack = (c_size_t*)c_Allocator_Calloc(&self->allocator, total_V, sizeof(c_size_t));
|
||
|
|
if (!reverse_stack) return C_ERR_NOMEM;
|
||
|
|
|
||
|
|
c_size_t stack_size = 0;
|
||
|
|
for (c_size_t x = v; x != self->s; x = self->edge_to[x]) {
|
||
|
|
reverse_stack[stack_size++] = x;
|
||
|
|
}
|
||
|
|
reverse_stack[stack_size++] = self->s;
|
||
|
|
|
||
|
|
c_err_t err = C_SUCCESS;
|
||
|
|
while (stack_size > 0) {
|
||
|
|
c_size_t current_vertex = reverse_stack[--stack_size];
|
||
|
|
err = c_VertexIdList_Append(out_path, (c_uint_t)current_vertex);
|
||
|
|
if (err != C_SUCCESS) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
c_Allocator_Free(&self->allocator, reverse_stack);
|
||
|
|
return err;
|
||
|
|
}
|