Files
cKit/Graph/c_Digraph.c
T
2026-09-07 18:48:16 +08:00

243 lines
7.7 KiB
C

#include <c_Digraph.h>
c_err_t c_Digraph_Init(c_Digraph_t* self, c_size_t V, c_Allocator_t* alloc) {
if (!self) return C_ERR_PARAM;
/* 1. 复制或初始化分配器 */
self->allocator = alloc ? *alloc : c_DefaultAllocator;
self->V = V;
self->E = 0;
self->adj_list = NULL;
self->indegree = NULL;
if (V > 0) {
/* 2. 分配邻接表骨架内存 */
self->adj_list = (c_AdjList_t*)c_Allocator_Calloc(&self->allocator, V, sizeof(c_AdjList_t));
if (!self->adj_list) return C_ERR_NOMEM;
/* 3. 分配入度计数数组内存 */
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;
}
/* 4. 初始化每个顶点的邻接表 */
for (c_size_t i = 0; i < V; ++i) {
c_AdjList_Init(&self->adj_list[i], 0, alloc);
}
}
return C_SUCCESS;
}
void c_Digraph_Destroy(c_Digraph_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->indegree) {
c_Allocator_Free(&self->allocator, self->indegree);
self->indegree = NULL;
}
self->V = 0;
self->E = 0;
}
c_err_t c_Digraph_AddEdge(c_Digraph_t* self, c_size_t from, c_size_t to) {
if (!self || from >= self->V || to >= self->V) {
return C_ERR_PARAM;
}
/* 往 from 节点的邻接表末尾追加 to 节点 */
c_err_t err = c_AdjList_Append(&self->adj_list[from], (c_uint_t)to);
if (err == C_SUCCESS) {
self->E++;
self->indegree[to]++; /* O(1) 同步更新入度计数 */
}
return err;
}
c_err_t c_Digraph_Resize(c_Digraph_t* self, c_size_t new_V) {
if (!self) return C_ERR_PARAM;
if (new_V == self->V) return C_SUCCESS;
if (new_V == 0) {
c_Digraph_Destroy(self);
return C_SUCCESS;
}
/* 1. 如果新尺寸变小,需先释放多余顶点的数组资源 */
if (new_V < self->V) {
for (c_size_t i = new_V; i < self->V; ++i) {
/* 注意:如果被删除的顶点包含出边,可能会导致其他顶点的入度不准确 */
/* 健壮的做法是在销毁前遍历这些出边,给对应目标的入度做减法 */
c_AdjList_t* adj = &self->adj_list[i];
c_size_t size = (c_size_t)c_AdjList_GetSize(adj);
for (c_size_t j = 0; j < size; ++j) {
c_size_t target;
if (c_AdjList_Get(adj, j, &target)!=C_ERR_OK) {
continue;
}
if (target < new_V) {
self->indegree[target]--;
self->E--;
}
}
c_AdjList_Destroy(&self->adj_list[i]);
}
}
/* 2. 重新调整邻接表骨架内存空间 */
c_AdjList_t* new_list = (c_AdjList_t*)c_Allocator_Realloc(
&self->allocator, self->adj_list,
self->V * sizeof(c_AdjList_t), new_V * sizeof(c_AdjList_t)
);
if (!new_list) return C_ERR_NOMEM;
self->adj_list = new_list;
/* 3. 重新调整入度数组内存空间 */
c_size_t* new_indegree = (c_size_t*)c_Allocator_Realloc(
&self->allocator, self->indegree,
self->V * sizeof(c_size_t), new_V * sizeof(c_size_t)
);
if (!new_indegree) return C_ERR_NOMEM;
self->indegree = new_indegree;
/* 4. 如果新尺寸变大,初始化新增加顶点的邻接表与入度计数 */
if (new_V > self->V) {
for (c_size_t i = self->V; i < new_V; ++i) {
memset(&self->adj_list[i], 0, sizeof(c_AdjList_t));
c_AdjList_Init(&self->adj_list[i], 0, &self->allocator);
self->indegree[i] = 0;
}
}
self->V = new_V;
return C_SUCCESS;
}
c_size_t c_Digraph_GetDegree(c_Digraph_t* self, c_size_t v, c_bool_t out_degree_only) {
if (!self || v >= self->V) return 0;
/* 1. 出度 (Out-Degree):直接获取该顶点邻接表的元素数量 */
if (out_degree_only) {
return (c_size_t)c_AdjList_GetSize(&self->adj_list[v]);
}
/* 2. 入度 (In-Degree):需要遍历整个图,统计有多少条边指向 v */
return self->indegree[v];
}
c_err_t c_Digraph_Reverse(c_Digraph_t* self, c_Digraph_t* out_reversed) {
if (!self || !out_reversed) return C_ERR_PARAM;
c_err_t err = c_Digraph_Init(out_reversed, self->V, &self->allocator);
if (err != C_SUCCESS) return err;
for (c_size_t u = 0; u < self->V; ++u) {
c_AdjList_t* adj = &self->adj_list[u];
c_size_t size = (c_size_t)c_AdjList_GetSize(adj);
for (c_size_t i = 0; i < size; ++i) {
c_size_t v;
if (c_AdjList_Get(adj, i, &v)!=C_ERR_OK) {
continue;
}
err = c_Digraph_AddEdge(out_reversed, v, u);
if (err != C_SUCCESS) {
c_Digraph_Destroy(out_reversed);
return err;
}
}
}
return C_SUCCESS;
}
/* ================================================================================================================== */
/* Unweighted Digraph Edge Query Primitive */
c_err_t c_Digraph_GetEdge(c_Digraph_t* self, c_size_t from, c_size_t to, c_size_t * edge_idx) {
if (!self ) return C_ERR_PARAM;
if (from >= self->V) return C_ERR_OUTOFBOUND;
c_AdjList_t* adj = &self->adj_list[from];
c_size_t size = (c_size_t)c_UIntArray_GetSize(adj);
c_uint_t target_value = 0;
for (c_size_t i=0; i<size; i++) {
c_err_t err = c_UIntArray_Get(adj, i, &target_value);
if (err==C_SUCCESS && target_value==to) {
if (edge_idx) {
*edge_idx = i;
}
return C_SUCCESS;
}
}
return C_ERR_NOTFOUND;
}
/* ================================================================================================================== */
/* Unweighted Digraph Edge Removal Primitive */
c_err_t c_Digraph_RemoveEdge(c_Digraph_t* self, c_size_t from, c_size_t to) {
if (!self) return C_ERR_PARAM;
if (from >= self->V || to >= self->V) return C_ERR_OUTOFBOUND;
c_AdjList_t* adj = &self->adj_list[from];
c_size_t size = (c_size_t)c_UIntArray_GetSize(adj);
c_bool_t found = C_FALSE;
/* Locate the target destination 'to' inside the out-list array */
for (c_size_t i = 0; i < size; ++i) {
c_uint_t generic_entry = 0;
if (c_UIntArray_Get(adj, i, &generic_entry) == C_SUCCESS) {
if ((c_size_t)generic_entry == to) {
/* Remove the entry element via your underlying array interface */
c_UIntArray_Remove(adj, i);
found = C_TRUE;
break;
}
}
}
if (found) {
if (self->E > 0) self->E--;
self->indegree[to]--;
return C_SUCCESS;
}
return C_ERR_NOTFOUND;
}
c_bool_t c_Digraph_HasEdge(const c_Digraph_t* self, c_size_t from, c_size_t to) {
if (!self || from >= self->V || to >= self->V) return C_FALSE;
const c_AdjList_t* adj = &self->adj_list[from];
c_size_t size = (c_size_t)c_UIntArray_GetSize((c_UIntArray_t*)adj);
/* Scan the adjacency out-list of vertex 'from' */
for (c_size_t i = 0; i < size; ++i) {
c_uint_t generic_val = 0;
/* Safely extract the adjacent vertex using your pointer specifications */
c_err_t err = c_UIntArray_Get((c_UIntArray_t*)adj, i, &generic_val);
if (err == C_SUCCESS && (c_size_t)generic_val == to) {
return C_TRUE; /* Edge found */
}
}
return C_FALSE; /* Edge does not exist */
}