#include c_err_t c_EdgeWeightedGraph_Init(c_EdgeWeightedGraph_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; if (V > 0) { /* Allocate dynamic adjacency list managers matching V size */ self->adj_list = c_Allocator_Calloc(&self->allocator, V, sizeof(c_UIntArray_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); } } return C_SUCCESS; } void c_EdgeWeightedGraph_Destroy(c_EdgeWeightedGraph_t* self) { if (!self) return; if (self->adj_list) { for (c_size_t i = 0; i < self->V; ++i) { c_AdjList_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; } self->V = 0; self->E = 0; self->edges_cap = 0; } c_err_t c_EdgeWeightedGraph_AddEdge(c_EdgeWeightedGraph_t* self, c_size_t v, c_size_t w, double weight) { if (!self || v >= self->V || w >= self->V) return C_ERR_PARAM; /* 1. Ensure the global edge pool buffer has enough memory 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_Edge_t* new_pool = (c_Edge_t*)c_Allocator_Realloc( &self->allocator, self->edges_pool, old_cap * sizeof(c_Edge_t), new_cap * sizeof(c_Edge_t) ); if (!new_pool) return C_ERR_NOMEM; self->edges_pool = new_pool; self->edges_cap = new_cap; } /* 2. Assign configuration details into the pool item slot */ c_size_t edge_id = self->E; self->edges_pool[edge_id] = (c_Edge_t){ .v = v, .w = w, .weight = weight }; /* 3. Append the structural reference pointer id into BOTH adjacent endpoint tracking arrays */ c_err_t err = c_AdjList_Append(&self->adj_list[v], (c_uint_t)edge_id); if (err != C_SUCCESS) return err; err = c_AdjList_Append(&self->adj_list[w], (c_uint_t)edge_id); if (err != C_SUCCESS) return err; self->E++; return C_SUCCESS; } c_err_t c_EdgeWeightedGraph_GetEdge(c_EdgeWeightedGraph_t* self, c_size_t edge_idx, c_Edge_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_EdgeWeightedGraph_RemoveEdge(c_EdgeWeightedGraph_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_Edge_t* edge = &self->edges_pool[edge_id]; /* If the edge is already soft-deleted, skip to prevent repetitive lookups */ if (edge->v == C_EDGE_SENTINEL) return C_SUCCESS; c_size_t vertex_v = edge->v; c_size_t vertex_w = edge->w; /* 2. Purge the edge_id reference from vertex v's adjacency list */ c_UIntArray_t* adj_v = &self->adj_list[vertex_v]; c_size_t size_v = (c_size_t)c_UIntArray_GetSize(adj_v); c_bool_t found_v = C_FALSE; for (c_size_t i = 0; i < size_v; ++i) { c_uint_t generic_id = 0; if (c_UIntArray_Get(adj_v, i, &generic_id) == C_SUCCESS) { if ((c_size_t)generic_id == edge_id) { c_UIntArray_Remove(adj_v, i); found_v = C_TRUE; break; } } } /* 3. Purge the edge_id reference from vertex w's adjacency list */ c_UIntArray_t* adj_w = &self->adj_list[vertex_w]; c_size_t size_w = (c_size_t)c_UIntArray_GetSize(adj_w); c_bool_t found_w = C_FALSE; for (c_size_t i = 0; i < size_w; ++i) { c_uint_t generic_id = 0; if (c_UIntArray_Get(adj_w, i, &generic_id) == C_SUCCESS) { if ((c_size_t)generic_id == edge_id) { c_UIntArray_Remove(adj_w, i); found_w = C_TRUE; break; } } } /* 4. Finalize soft-deletion updates inside the pool slot */ if (found_v || found_w) { edge->v = C_EDGE_SENTINEL; edge->w = C_EDGE_SENTINEL; edge->weight = 0.0; } else { return C_ERR_NOTFOUND; } return C_SUCCESS; }