#include #include typedef struct { c_size_t v; /* Current vertex */ c_size_t edge_idx; /* Next neighbor index to examine in the adjacency list */ } c_TarjanFrame_t; /* Private iterative DFS engine subroutine */ static void c_NonrecursiveTarjanSCC_Process(c_NonrecursiveTarjanSCC_t* self, c_Digraph_t* graph, c_size_t root, c_TarjanFrame_t* frame_stack) { c_size_t frame_stack_size = 0; /* Push the initial root activation frame entry */ self->marked[root] = C_TRUE; self->pre[root] = self->pre_counter++; self->low[root] = self->pre[root]; self->stack[self->stack_size++] = root; self->on_stack[root] = C_TRUE; frame_stack[frame_stack_size++] = (c_TarjanFrame_t){ .v = root, .edge_idx = 0 }; while (frame_stack_size > 0) { c_TarjanFrame_t* current_frame = &frame_stack[frame_stack_size - 1]; 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); c_bool_t advanced = C_FALSE; while (current_frame->edge_idx < neighbor_count) { c_uint_t target_value = 0; c_err_t err = c_AdjList_Get(adj, current_frame->edge_idx, &target_value); current_frame->edge_idx++; /* Advance edge iterator pointer state */ if (err == C_SUCCESS) { c_size_t w = (c_size_t)target_value; if (!self->marked[w]) { self->marked[w] = C_TRUE; self->pre[w] = self->pre_counter++; self->low[w] = self->pre[w]; self->stack[self->stack_size++] = w; self->on_stack[w] = C_TRUE; /* Push new execution frame onto the state stack (Simulating Recursive Call) */ frame_stack[frame_stack_size++] = (c_TarjanFrame_t){ .v = w, .edge_idx = 0 }; advanced = C_TRUE; break; } else if (self->on_stack[w]) { self->low[u] = C_MIN(self->low[u], self->pre[w]); } } } if (advanced) continue; /* Yield control forward down into the child node branch */ /* Post-visit Processing (Equivalent to tracking back up the recursive unwinding stack) */ frame_stack_size--; /* Pop frame context */ if (frame_stack_size > 0) { c_size_t parent = frame_stack[frame_stack_size - 1].v; self->low[parent] = C_MIN(self->low[parent], self->low[u]); } /* If u is a root node of an SCC, pop all component nodes off the membership tracker */ if (self->low[u] == self->pre[u]) { c_size_t component_node = 0; do { component_node = self->stack[--self->stack_size]; self->id[component_node] = self->count; self->on_stack[component_node] = C_FALSE; } while (component_node != u); self->count++; /* Advance component group numbering identity mapping */ } } } c_err_t c_NonrecursiveTarjanSCC_Init(c_NonrecursiveTarjanSCC_t* self, c_Digraph_t* graph, c_Allocator_t* allocator) { if (!self || !graph) return C_ERR_PARAM; self->allocator = allocator ? *allocator : c_DefaultAllocator; self->count = 0; self->pre_counter = 0; self->stack_size = 0; self->V = graph->V; if (self->V == 0) return C_SUCCESS; self->marked = (c_bool_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_bool_t)); self->id = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); self->pre = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); self->low = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); self->stack = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t)); self->on_stack = (c_bool_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_bool_t)); if (!self->marked || !self->id || !self->pre || !self->low || !self->stack || !self->on_stack) { c_NonrecursiveTarjanSCC_Destroy(self); return C_ERR_NOMEM; } /* Allocate local frame execution engine tracking context sized O(V) */ c_TarjanFrame_t* frame_stack = (c_TarjanFrame_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_TarjanFrame_t)); if (!frame_stack) { c_NonrecursiveTarjanSCC_Destroy(self); return C_ERR_NOMEM; } for (c_size_t v = 0; v < self->V; ++v) { if (!self->marked[v]) { c_NonrecursiveTarjanSCC_Process(self, graph, v, frame_stack); } } c_Allocator_Free(&self->allocator, frame_stack); return C_SUCCESS; } void c_NonrecursiveTarjanSCC_Destroy(c_NonrecursiveTarjanSCC_t* self) { if (!self) return; if (self->marked) c_Allocator_Free(&self->allocator, self->marked); if (self->id) c_Allocator_Free(&self->allocator, self->id); if (self->pre) c_Allocator_Free(&self->allocator, self->pre); if (self->low) c_Allocator_Free(&self->allocator, self->low); if (self->stack) c_Allocator_Free(&self->allocator, self->stack); if (self->on_stack) c_Allocator_Free(&self->allocator, self->on_stack); self->marked = NULL; self->id = NULL; self->pre = NULL; self->low = NULL; self->stack = NULL; self->on_stack = NULL; self->count = 0; self->stack_size = 0; self->V = 0; }