106 lines
3.7 KiB
C
106 lines
3.7 KiB
C
#include <c_GabowSCC.h>
|
|||
|
|
|
||
|
|
|
||
|
|
static void c_GabowSCC_DFS(c_GabowSCC_t* self, c_Digraph_t* graph, c_size_t v) {
|
||
|
|
self->marked[v] = C_TRUE;
|
||
|
|
self->pre[v] = self->pre_counter++;
|
||
|
|
|
||
|
|
/* Push onto both structural tracking stacks */
|
||
|
|
self->scc_stack[self->scc_stack_sz++] = v;
|
||
|
|
self->path_stack[self->path_stack_sz++] = v;
|
||
|
|
|
||
|
|
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;
|
||
|
|
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]) {
|
||
|
|
c_GabowSCC_DFS(self, graph, w);
|
||
|
|
}
|
||
|
|
/* If already visited but not yet assigned to an SCC component */
|
||
|
|
else if (self->id[w] == C_SIZE_MAX) {
|
||
|
|
/* Pop vertices from path_stack whose pre-order numbers are greater than pre[w] */
|
||
|
|
while (self->path_stack_sz > 0 && self->pre[self->path_stack[self->path_stack_sz - 1]] > self->pre[w]) {
|
||
|
|
self->path_stack_sz--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* If v is the root of an SCC component block, pop the complete component cluster */
|
||
|
|
if (self->path_stack_sz > 0 && self->path_stack[self->path_stack_sz - 1] == v) {
|
||
|
|
self->path_stack_sz--; /* Remove v from the root boundary stack */
|
||
|
|
|
||
|
|
c_size_t w = 0;
|
||
|
|
do {
|
||
|
|
w = self->scc_stack[--self->scc_stack_sz];
|
||
|
|
self->id[w] = self->count;
|
||
|
|
} while (w != v);
|
||
|
|
|
||
|
|
self->count++; /* Increment structural component counter group */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
c_err_t c_GabowSCC_Init(c_GabowSCC_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->scc_stack_sz = 0;
|
||
|
|
self->path_stack_sz = 0;
|
||
|
|
self->V = graph->V;
|
||
|
|
|
||
|
|
if (self->V == 0) return C_SUCCESS;
|
||
|
|
|
||
|
|
/* 1. Allocate tracked execution matrices arrays */
|
||
|
|
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->scc_stack = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t));
|
||
|
|
self->path_stack = (c_size_t*)c_Allocator_Calloc(&self->allocator, self->V, sizeof(c_size_t));
|
||
|
|
|
||
|
|
if (!self->marked || !self->id || !self->pre || !self->scc_stack || !self->path_stack) {
|
||
|
|
c_GabowSCC_Destroy(self);
|
||
|
|
return C_ERR_NOMEM;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Initialize all ID components to unassigned boundary sentinel state */
|
||
|
|
for (c_size_t i = 0; i < self->V; ++i) {
|
||
|
|
self->id[i] = C_SIZE_MAX;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 2. Process all components loops securely */
|
||
|
|
for (c_size_t v = 0; v < self->V; ++v) {
|
||
|
|
if (!self->marked[v]) {
|
||
|
|
c_GabowSCC_DFS(self, graph, v);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return C_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
void c_GabowSCC_Destroy(c_GabowSCC_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->scc_stack) c_Allocator_Free(&self->allocator, self->scc_stack);
|
||
|
|
if (self->path_stack) c_Allocator_Free(&self->allocator, self->path_stack);
|
||
|
|
|
||
|
|
self->marked = NULL;
|
||
|
|
self->id = NULL;
|
||
|
|
self->pre = NULL;
|
||
|
|
self->scc_stack = NULL;
|
||
|
|
self->path_stack = NULL;
|
||
|
|
self->count = 0;
|
||
|
|
self->scc_stack_sz = 0;
|
||
|
|
self->path_stack_sz = 0;
|
||
|
|
self->V = 0;
|
||
|
|
}
|