#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); }