#include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ // Internal deep structural trace walker that marks vertices within a cluster component static void c_CC_DFS_Internal(c_CC_t* self, const c_Graph_t* G, c_VertexId_t v, c_VertexId_t current_id) { self->marked[v] = C_TRUE; self->id[v] = current_id; self->size[current_id]++; // Access the array-backed adjacency list through the internal graph helper c_AdjList_t* list = c_Graph_GetAdjList((c_Graph_t*)G, v); if (!list) return; // Cache-friendly sequential sweep over flat neighbor array blocks for (c_size_t i = 0; i < list->size; i++) { c_VertexId_t w = (c_VertexId_t)list->array[i]; if (!self->marked[w]) { c_CC_DFS_Internal(self, G, w, current_id); } } } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_err_t c_CC_Init(c_CC_t* self, const c_Graph_t* G, c_Allocator_t* allocator) { if (!self || !G ) { return C_ERR_PARAM; } self->allocator = allocator?*allocator:c_DefaultAllocator; self->count = 0; self->marked = NULL; self->id = NULL; self->size = NULL; self->V = G->V; if (G->V == 0) { return C_SUCCESS; } // Allocate structural metadata array blocks via your custom allocator abstraction layer self->marked = (c_bool_t*)c_Allocator_Alloc(&self->allocator, G->V * sizeof(*self->marked)); self->id = (c_size_t*)c_Allocator_Alloc(&self->allocator, G->V * sizeof(*self->id)); self->size = (c_size_t*)c_Allocator_Alloc(&self->allocator, G->V * sizeof(*self->size)); if (!self->marked || !self->id || !self->size) { c_CC_Destroy(self); return C_ERR_NOMEM; } // Zero out state maps cleanly memset(self->marked, 0, G->V * sizeof(*self->marked)); memset(self->id, 0, G->V * sizeof(*self->id)); memset(self->size, 0, G->V * sizeof(*self->size)); // Run partition sweeps over all available unvisited structural nodes for (c_VertexId_t v = 0; v < G->V; v++) { if (!self->marked[v]) { c_CC_DFS_Internal(self, G, v, self->count); self->count++; } } return C_SUCCESS; } void c_CC_Destroy(c_CC_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->size) c_Allocator_Free(&self->allocator, self->size); self->marked = NULL; self->id = NULL; self->size = NULL; self->count = 0; self->V = 0; } c_bool_t c_CC_Connected(const c_CC_t* self, c_VertexId_t v, c_VertexId_t w) { // Parameter boundary filter protection using the internally cached V if (!self || v >= self->V || w >= self->V || !self->id) { return C_FALSE; } return self->id[v] == self->id[w]; } c_size_t c_CC_Id(const c_CC_t* self, c_VertexId_t v) { if (!self || v >= self->V || !self->id) { return 0; // Return safe default index bounds if lookup fails } return self->id[v]; } c_size_t c_CC_Size(const c_CC_t* self, c_VertexId_t v) { if (!self || v >= self->V || !self->id || !self->size) { return 0; } return self->size[self->id[v]]; } c_size_t c_CC_Count(const c_CC_t* self) { if (!self) return 0; return self->count; }