Graph
This commit is contained in:
+110
@@ -0,0 +1,110 @@
|
||||
#include <c_CC.h>
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user