Files
cKit/Graph/c_EdgeWeightedDigraph.c
T

162 lines
5.1 KiB
C
Raw Normal View History

2026-09-07 18:48:16 +08:00
#include <c_EdgeWeightedDigraph.h>
c_err_t c_EdgeWeightedDigraph_Init(c_EdgeWeightedDigraph_t* self, c_size_t V, c_Allocator_t* alloc) {
if (!self) return C_ERR_PARAM;
self->allocator = alloc ? *alloc : c_DefaultAllocator;
self->V = V;
self->E = 0;
self->adj_list = NULL;
self->edges_pool = NULL;
self->edges_cap = 0;
self->indegree = NULL;
if (V > 0) {
/* Allocate dynamic adjacency list managers matching V size */
self->adj_list = c_Allocator_Calloc(&self->allocator, V, sizeof(c_AdjList_t));
if (!self->adj_list) return C_ERR_NOMEM;
for (c_size_t i = 0; i < V; ++i) {
c_AdjList_Init(&self->adj_list[i],0, alloc);
}
/* Allocate the specialized O(1) in-degree cache array */
self->indegree = (c_size_t*)c_Allocator_Calloc(&self->allocator, V, sizeof(c_size_t));
if (!self->indegree) {
c_Allocator_Free(&self->allocator, self->adj_list);
self->adj_list = NULL;
return C_ERR_NOMEM;
}
}
return C_SUCCESS;
}
void c_EdgeWeightedDigraph_Destroy(c_EdgeWeightedDigraph_t* self) {
if (!self) return;
if (self->adj_list) {
for (c_size_t i = 0; i < self->V; ++i) {
c_UIntArray_Destroy(&self->adj_list[i]);
}
c_Allocator_Free(&self->allocator, self->adj_list);
self->adj_list = NULL;
}
if (self->edges_pool) {
c_Allocator_Free(&self->allocator, self->edges_pool);
self->edges_pool = NULL;
}
if (self->indegree) {
c_Allocator_Free(&self->allocator, self->indegree);
self->indegree = NULL;
}
self->V = 0;
self->E = 0;
self->edges_cap = 0;
c_Allocator_Destroy(&self->allocator);
}
c_err_t c_EdgeWeightedDigraph_AddEdge(c_EdgeWeightedDigraph_t* self, c_size_t from, c_size_t to, double weight) {
if (!self || from >= self->V || to >= self->V) return C_ERR_PARAM;
/* 1. Ensure the global directed edge pool has sufficient capacity */
if (self->E >= self->edges_cap) {
c_size_t old_cap = self->edges_cap;
c_size_t new_cap = (old_cap == 0) ? 4 : (old_cap * 2);
c_DirectedEdge_t* new_pool = (c_DirectedEdge_t*)c_Allocator_Realloc(
&self->allocator,
self->edges_pool,
old_cap * sizeof(c_DirectedEdge_t),
new_cap * sizeof(c_DirectedEdge_t)
);
if (!new_pool) return C_ERR_NOMEM;
self->edges_pool = new_pool;
self->edges_cap = new_cap;
}
/* 2. Populate the edge metadata inside the pool slot */
c_size_t edge_id = self->E;
self->edges_pool[edge_id] = (c_DirectedEdge_t){ .from = from, .to = to, .weight = weight };
/* 3. Append the edge_id reference to the source vertex's adjacency out-list */
c_err_t err = c_AdjList_Append(&self->adj_list[from], (c_uint_t)edge_id);
if (err != C_SUCCESS) return err;
/* 4. Update the cached in-degree tracking array counter at the destination vertex */
self->indegree[to]++;
self->E++;
return C_SUCCESS;
}
c_err_t c_EdgeWeightedDigraph_GetEdge(c_EdgeWeightedDigraph_t* self, c_size_t edge_idx, c_DirectedEdge_t* edge) {
if (!self ) return C_ERR_PARAM;
/* Strict firewall boundary validation against the total allocated edge count */
if (edge_idx >= self->E) return C_ERR_OUTOFBOUND;
/* Execute a fast bitwise block-copy of the edge object contents */
if (edge) {
*edge = self->edges_pool[edge_idx];
}
return C_SUCCESS;
}
c_err_t c_EdgeWeightedDigraph_RemoveEdge(c_EdgeWeightedDigraph_t* self, c_size_t edge_id) {
if (!self) return C_ERR_PARAM;
/* 1. Bounds check firewall validation */
if (edge_id >= self->E) return C_ERR_OUTOFBOUND;
c_DirectedEdge_t* edge = &self->edges_pool[edge_id];
/* If the edge is already soft-deleted, skip to avoid double decrement corruptions */
if (edge->from == C_DIRECTED_EDGE_SENTINEL) return C_SUCCESS;
c_size_t from_vertex = edge->from;
c_size_t to_vertex = edge->to;
/* 2. Locate and purge the edge_id reference out from the source's adj_list */
c_UIntArray_t* adj = &self->adj_list[from_vertex];
c_size_t adj_size = (c_size_t)c_UIntArray_GetSize(adj);
c_bool_t found = C_FALSE;
for (c_size_t i = 0; i < adj_size; ++i) {
c_uint_t generic_id = 0;
if (c_UIntArray_Get(adj, i, &generic_id) == C_SUCCESS) {
if ((c_size_t)generic_id == edge_id) {
/* Assuming your modular c_UIntArray layout supports safe positional removals */
c_UIntArray_Remove(adj, i);
found = C_TRUE;
break;
}
}
}
/* 3. Finalize accounting updates if the target link was successfully detached */
if (found) {
/* Soft-delete the pool metadata content attributes */
edge->from = C_DIRECTED_EDGE_SENTINEL;
edge->to = C_DIRECTED_EDGE_SENTINEL;
edge->weight = 0.0;
/* Decrement your O(1) optimized in-degree tracker */
if (self->indegree[to_vertex] > 0) {
self->indegree[to_vertex]--;
}
} else {
return C_ERR_NOTFOUND;
}
return C_SUCCESS;
}