Prim 最小生成树算法

Prim 算法可视化演示

控制面板


候选边列表

MST 边集

算法步骤提示

请点击“生成示例图”开始。

Prim 算法 C++ 实现 (优先队列优化)

// C++ 实现 Prim 算法查找最小生成树 (使用优先队列优化)
#include <bits/stdc++.h>
using namespace std;

// 定义无穷大常量
const int INF = INT_MAX
// 定义图的边结构
struct Edge {
    int to;     // 边的终点
    int weight; // 边的权重

    // 重载大于运算符,用于优先队列(最小堆)
    // 注意:优先队列默认是最大堆,所以要反向定义比较逻辑
    bool operator>(const Edge& other) const {
        return weight > other.weight;
    }
};

// 定义用于存储MST结果的边
struct MSTEdge {
    int u, v, weight;
};

// Prim 算法函数
vector primMST(int startNode, int V, const map>& adjList) {
    // 存储到各个顶点的最小权重,初始化为无穷大
    vector minWeight(V, INF);
    // 存储生成树中每个顶点的前驱顶点,初始化为-1
    vector parent(V, -1);
    // 标记顶点是否已经加入MST,初始化为 false
    vector inMST(V, false);
    // 存储最终MST的边
    vector resultMST;
    // 记录MST的总权重
    long long totalWeight = 0;

    // 使用优先队列存储候选边 {权重, 目标顶点}
    // C++ 的 priority_queue 默认是最大堆,我们需要最小堆
    // 存储 Edge 结构,并使用自定义的 > 运算符
    priority_queue, greater> pq;

    // 算法从起始顶点开始
    minWeight[startNode] = 0;
    pq.push({startNode, 0}); // {目标顶点, 权重} - 初始权重为0

    while (!pq.empty()) {
        // 从优先队列中取出当前权重最小的边连接的顶点
        Edge current = pq.top();
        pq.pop();
        int u = current.to;
        int w = current.weight; // 这是到达 u 的最小权重

        // 如果顶点 u 已经被访问过(或者这条边是旧的、权重更大的边),则跳过
        if (inMST[u] || w > minWeight[u]) {
            continue;
        }

        // 将顶点 u 加入 MST
        inMST[u] = true;
        totalWeight += w; // 累加权重

        // 如果 u 不是起始节点 (parent[u] != -1),则将边 (parent[u], u) 加入结果集
        if (parent[u] != -1) {
            resultMST.push_back({parent[u], u, w});
        }

        // 遍历与 u 相邻的所有顶点 v
        if (adjList.count(u)) { // 检查 u 是否有邻接边
            for (const auto& edge : adjList.at(u)) {
                int v = edge.to;
                int edgeWeight = edge.weight;

                // 如果顶点 v 不在 MST 中,并且通过 u 到达 v 的权重更小
                if (!inMST[v] && edgeWeight < minWeight[v]) {
                    // 更新到达 v 的最小权重
                    minWeight[v] = edgeWeight;
                    // 更新 v 的父节点为 u
                    parent[v] = u;
                    // 将新的候选边 {v, minWeight[v]} 加入优先队列
                    pq.push({v, minWeight[v]});
                }
            }
        }
    }

    // 检查是否所有顶点都已连接 (适用于图不连通的情况)
    // if (resultMST.size() < V - 1) {
    //     cout << "图不连通,无法生成覆盖所有顶点的MST" << endl;
    // }

    cout << "Prim 算法完成。最小生成树总权重: " << totalWeight << endl;
    return resultMST;
}

// --- 示例用法 ---
// int main() {
//     int V = 6; // 顶点数 (0 到 5)
//     map> adjList; // 邻接列表

//     // 添加边 (无向图,需要双向添加)
//     auto addEdge = [&](int u, int v, int w) {
//         adjList[u].push_back({v, w});
//         adjList[v].push_back({u, w});
//     };

//     addEdge(0, 1, 4); addEdge(0, 2, 3);
//     addEdge(1, 2, 1); addEdge(1, 3, 2);
//     addEdge(2, 3, 4); addEdge(2, 4, 3);
//     addEdge(3, 4, 2); addEdge(3, 5, 5);
//     addEdge(4, 5, 6);

//     int startNode = 0; // 选择起始节点
//     vector mst = primMST(startNode, V, adjList);

//     cout << "\n最小生成树的边:" << endl;
//     for (const auto& edge : mst) {
//         cout << edge.u << " -- " << edge.v << " (权重: " << edge.weight << ")" << endl;
//     }

//     return 0;
// }