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

90 lines
2.9 KiB
C

#include "c_KruskalMST.h"
#include "c_MinPQ.h"
#include "c_QuickFindUF.h" /* Direct inline layout consumption */
/* ================================================================================================================== */
/* Private Sort Comparator for c_MinPQ_t matching edge priorities */
static int c_Kruskal_EdgeCompare(const void* a, const void* b, void* args) {
c_size_t id_a = *(const c_size_t*)a;
c_size_t id_b = *(const c_size_t*)b;
c_Edge_t* pool = (c_Edge_t*)args;
double weight_a = pool[id_a].weight;
double weight_b = pool[id_b].weight;
return (weight_a > weight_b) - (weight_a < weight_b);
}
/* ================================================================================================================== */
/* Core Kruskal MST Initializer Processing Routine */
c_err_t c_KruskalMST_Init(c_KruskalMST_t* self, c_EdgeWeightedGraph_t* graph, c_Allocator_t* allocator) {
if (!self || !graph) return C_ERR_PARAM;
self->allocator = allocator ? *allocator : c_DefaultAllocator;
self->weight = 0.0;
c_VertexIdList_Init(&self->mst_edges, 0, allocator);
if (graph->V == 0 || graph->E == 0) return C_SUCCESS;
/* 1. Build a priority queue containing all edge indices to sort them automatically */
c_MinPQ_t pq;
c_err_t err = c_MinPQ_Init(
&pq,
graph->E,
sizeof(c_size_t),
c_Kruskal_EdgeCompare,
graph->edges_pool,
allocator
);
if (err != C_SUCCESS) return err;
/* Seed the PQ with every single unique edge index */
for (c_size_t i = 0; i < graph->E; ++i) {
c_MinPQ_Push(&pq, &i);
}
/* 2. Configure your specific c_QuickFindUF data structure */
c_QuickFindUF_t uf;
err = c_QuickFindUF_Init(&uf, graph->V, allocator);
if (err != C_SUCCESS) {
c_MinPQ_Destroy(&pq);
return err;
}
/* 3. Main processing loop: extract edges in ascending order of weight */
while (!c_MinPQ_IsEmpty(&pq) && c_VertexIdList_GetSize(&self->mst_edges) < graph->V - 1) {
c_size_t edge_id = 0;
c_MinPQ_Pop(&pq, &edge_id);
c_Edge_t* edge = &graph->edges_pool[edge_id];
c_size_t v = edge->v;
c_size_t w = edge->w;
/* If v and w are not already connected, adding this edge is safe (no cycle created) */
if (!c_QuickFindUF_IsConnected(&uf, v, w)) {
c_QuickFindUF_Union(&uf, v, w);
c_VertexIdList_Append(&self->mst_edges, (c_uint_t)edge_id);
self->weight += edge->weight;
}
}
/* Clean up working structures */
c_QuickFindUF_Destroy(&uf);
c_MinPQ_Destroy(&pq);
return C_SUCCESS;
}
void c_KruskalMST_Destroy(c_KruskalMST_t* self) {
if (!self) return;
c_VertexIdList_Destroy(&self->mst_edges);
self->weight = 0.0;
}
c_err_t c_KruskalMST_GetEdges(c_KruskalMST_t* self, c_VertexIdList_t* out_edges) {
if (!self || !out_edges) return C_ERR_PARAM;
return c_VertexIdList_Copy(out_edges, &self->mst_edges);
}