Kruskal算法详解:最小生成树的实现

这段代码实现了Kruskal算法,用于求解一个连通无向图的最小生成树。

void Kruskal(Graph *graph) {
    // 按权值从小到大排序
    qsort(graph->edges, graph->edgeNum, sizeof(Edge), cmp);
    // 初始化并查集
    UnionFindSet set;
    MakeSet(&set, graph->vertexNum);
    // 记录删除的边
    Edge removedEdges[MAX_EDGE_NUM];
    int removedEdgeNum = 0;
    // 遍历所有边
    for (int i = 0; i < graph->edgeNum; i++) {
        Edge e = graph->edges[i];
        // 如果边的两个端点不在同一个集合中,说明不会形成环,可以加入最小生成树中
        if (Find(&set, e.tail) != Find(&set, e.head)) {
            Union(&set, e.tail, e.head);
            printf('边 (%d, %d) 权值为 %d 加入最小生成树\n', e.tail, e.head, e.weight);
        } else {
            // 否则,删除边
            removedEdges[removedEdgeNum++] = e;
        }
    }
}

代码解析:

  1. 排序: qsort(graph->edges, graph->edgeNum, sizeof(Edge), cmp); 首先将图中的边按照权值从小到大进行排序,以便后续的遍历。
  2. 初始化并查集: UnionFindSet set; MakeSet(&set, graph->vertexNum); 使用并查集来维护图中的连通性,初始化并查集时将每个顶点都看作一个单独的集合。
  3. 遍历所有边: for (int i = 0; i < graph->edgeNum; i++) { ... } 循环遍历所有边,对每条边进行判断和处理。
  4. 判断环路: if (Find(&set, e.tail) != Find(&set, e.head)) { ... } 使用 Find 函数判断边的两个端点是否在同一个集合中。如果不在,则说明加入这条边不会形成环,可以加入最小生成树中。
  5. 加入最小生成树: Union(&set, e.tail, e.head); printf('边 (%d, %d) 权值为 %d 加入最小生成树\n', e.tail, e.head, e.weight); 将这条边加入最小生成树中,并将这两个端点所在的集合合并。
  6. 删除边: else { removedEdges[removedEdgeNum++] = e; } 如果边的两个端点在同一个集合中,则说明加入这条边会形成环,因此将这条边删除,并将其记录在 removedEdges 数组中。

代码说明:

  • graph->edges 表示图的所有边,graph->edgeNum 表示边的数量。
  • Edge 结构体表示一条边,包含 tail(起点)、head(终点)、weight(权值)等信息。
  • UnionFindSet 结构体表示并查集,用于维护图的连通性。
  • MakeSet 函数用于初始化并查集。
  • Find 函数用于查找一个顶点所在的集合。
  • Union 函数用于合并两个集合。
  • removedEdges 数组用于记录被删除的边。

扩展应用:

如果需要求解原图的最小生成树,则可以在遍历完所有边之后,将 removedEdges 数组中的边重新加入图中,并再次运行Kruskal算法即可。


原文地址: https://www.cveoy.top/t/topic/fXtV 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录