89 lines
2.8 KiB
C
89 lines
2.8 KiB
C
#include <c_NonrecursiveDirectedDFS.h>
|
|
#include <c_ArrayStack.h>
|
|
|
|
typedef struct {
|
|
c_size_t v; /* Current vertex */
|
|
c_size_t edge_idx; /* Next neighbor index to examine in the adjacency list */
|
|
} c_DFSFrame_t;
|
|
|
|
c_err_t c_NonrecursiveDirectedDFS_Init(c_NonrecursiveDirectedDFS_t* self, 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->count = 0;
|
|
|
|
/* 1. Allocate the visited tracking array */
|
|
self->marked = (c_bool_t*)c_Allocator_Calloc(&self->allocator, graph->V, sizeof(c_bool_t));
|
|
if (!self->marked) return C_ERR_NOMEM;
|
|
|
|
/* 2. Allocate an explicit execution stack bounded exactly by the number of vertices O(V) */
|
|
c_DFSFrame_t frame={0};
|
|
|
|
c_ArrayStack_t stack;
|
|
c_err_t err = c_ArrayStack_Init(&stack, sizeof(c_DFSFrame_t), 0, allocator);
|
|
if (err!=C_ERR_OK) {
|
|
c_Allocator_Free(&self->allocator, self->marked);
|
|
self->marked = NULL;
|
|
return err;
|
|
}
|
|
|
|
/* Push the initial source vertex frame onto our stack */
|
|
self->marked[s] = C_TRUE;
|
|
self->count++;
|
|
|
|
frame.v = s;
|
|
frame.edge_idx = 0;
|
|
c_ArrayStack_Push(&stack, &frame);
|
|
|
|
/* 3. Non-recursive processing loop */
|
|
while (!c_ArrayStack_IsEmpty(&stack)) {
|
|
/* Peek the top frame */
|
|
c_DFSFrame_t* current_frame = c_ArrayStack_Peek(&stack);
|
|
|
|
c_size_t u = current_frame->v;
|
|
|
|
c_AdjList_t* adj = &graph->adj_list[u];
|
|
c_size_t neighbor_count = (c_size_t)c_AdjList_GetSize(adj);
|
|
|
|
/* Advance down the adjacency list until we find an unvisited neighbor or finish the list */
|
|
c_bool_t advanced = C_FALSE;
|
|
while (current_frame->edge_idx < neighbor_count) {
|
|
c_size_t w;
|
|
c_AdjList_Get(adj, current_frame->edge_idx, &w);
|
|
current_frame->edge_idx++; /* Increment pointer for next pass */
|
|
|
|
if (!self->marked[w]) {
|
|
self->marked[w] = C_TRUE;
|
|
self->count++;
|
|
|
|
/* Push new frame onto the stack (equivalent to recursive call invocation) */
|
|
frame.v = w;
|
|
frame.edge_idx = 0;
|
|
c_ArrayStack_Push(&stack, &frame);
|
|
|
|
advanced = C_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we explored all neighbors of vertex u, pop it from the stack */
|
|
if (!advanced) {
|
|
c_ArrayStack_Pop(&stack, 0);
|
|
}
|
|
}
|
|
|
|
/* Clean up the runtime frame stack buffer */
|
|
c_ArrayStack_Destroy(&stack);
|
|
return C_SUCCESS;
|
|
}
|
|
|
|
void c_NonrecursiveDirectedDFS_Destroy(c_NonrecursiveDirectedDFS_t* self) {
|
|
if (!self) return;
|
|
if (self->marked) {
|
|
c_Allocator_Free(&self->allocator, self->marked);
|
|
self->marked = NULL;
|
|
}
|
|
self->count = 0;
|
|
}
|
|
|