Graph
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user