最小生成树——Prim算法

一、核心思想解析

Prim算法基于贪心策略,通过以下步骤构建最小生成树:

  1. 初始化阶段

    • 任选起始顶点加入MST集合
    • 创建候选边集合(连接已选与未选顶点的边)
  2. 迭代扩展过程

    • 每次选择候选边中权重最小的边
    • 将新顶点加入MST集合
    • 更新候选边集合
  3. 终止条件

    • 当所有顶点都加入MST时结束
    • 最终边集构成最小生成树

二、算法关键特性

时间复杂度分析

  • 基础实现(邻接矩阵):O(V²) → 适合稠密图
  • 优先队列优化(邻接表):O(E log V) → 适合稀疏图
  • 斐波那契堆优化:O(E + V log V) → 理论最优

空间复杂度

  • 邻接表存储:O(V + E)
  • 辅助数据结构:O(V)

适用场景

  • 通信网络布线优化
  • 交通枢纽连接规划
  • 电力网络拓扑构建
  • 物联网设备组网

核心限制

  • 仅适用于带权无向连通图
  • 无法处理负权边(需用其他算法)

三、代码实现示例

Python版本

import heapq

def prim(graph):
    """
    使用 Prim 算法计算加权无向图的最小生成树
    
    参数:
    graph (dict): 邻接表表示的图,格式为 {节点: [(邻接节点, 边权重), ...]}
    
    返回:
    list: 最小生成树的边列表,每条边格式为 (权重, 节点1, 节点2)
    """
    if not graph:
        return []
    
    # 选择任意节点作为起始点
    start_node = next(iter(graph))
    visited = {start_node}
    edges = []  # 存储 MST 的边
    heap = []   # 优先队列,存储候选边
    
    # 初始化优先队列
    for neighbor, weight in graph[start_node]:
        heapq.heappush(heap, (weight, start_node, neighbor))
    
    while heap and len(visited) < len(graph):
        weight, u, v = heapq.heappop(heap)
        
        # 如果目标节点已访问,则跳过
        if v in visited:
            continue
        
        # 将边加入 MST,并标记节点为已访问
        edges.append((weight, u, v))
        visited.add(v)
        
        # 将新节点的所有邻接边加入优先队列
        for neighbor, w in graph[v]:
            if neighbor not in visited:
                heapq.heappush(heap, (w, v, neighbor))
    
    return edges

C++版本

#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set>
#include <utility>
#include <string>

using namespace std;

// 定义边的结构,包含目标节点和权重
struct Edge {
    string to;
    int weight;
};

// 定义优先队列中的元素,包含权重、源节点和目标节点
struct QueueElement {
    int weight;
    string from;
    string to;
    
    // 重载比较运算符,使优先队列按权重从小到大排序
    bool operator>(const QueueElement& other) const {
        return weight > other.weight;
    }
};

// Prim 算法实现
vector<pair<int, pair<string, string>>> prim(const unordered_map<string, vector<Edge>>& graph) {
    vector<pair<int, pair<string, string>>> mst;  // 存储 MST 的边
    if (graph.empty()) return mst;
    
    // 选择任意节点作为起始点
    string start_node = graph.begin()->first;
    unordered_set<string> visited;
    visited.insert(start_node);
    
    // 优先队列,存储候选边
    priority_queue<QueueElement, vector<QueueElement>, greater<QueueElement>> heap;
    
    // 初始化优先队列
    for (const auto& edge : graph.at(start_node)) {
        heap.push({edge.weight, start_node, edge.to});
    }
    
    while (!heap.empty() && visited.size() < graph.size()) {
        QueueElement current = heap.top();
        heap.pop();
        
        // 如果目标节点已访问,则跳过
        if (visited.find(current.to) != visited.end()) {
            continue;
        }
        
        // 将边加入 MST,并标记节点为已访问
        mst.push_back({current.weight, {current.from, current.to}});
        visited.insert(current.to);
        
        // 将新节点的所有邻接边加入优先队列
        for (const auto& edge : graph.at(current.to)) {
            if (visited.find(edge.to) == visited.end()) {
                heap.push({edge.weight, current.to, edge.to});
            }
        }
    }
    
    return mst;
}

四、时间复杂度深度分析

基础实现分析

  • 每次选择最小边需要O(V)时间
  • 总迭代次数为V次
  • 最终复杂度:O(V²)
  • 最佳场景:完全图或邻接矩阵存储

优先队列优化

  • 堆作成本:每次插入/删除O(log E)
  • 边处理次数:最多E次
  • 最终复杂度:O(E log E) → 可优化为O(E log V)
  • 优势场景:稀疏图(E << V²)

斐波那契堆优化

  • 降低减少键作成本至O(1)
  • 理论最优复杂度:O(E + V log V)
  • 实际应用:超大规模图处

 

五、总结

  • Python 版本:使用heapq库实现优先队列,通过字典和元组表示图结构与边,简洁直观。
  • C++ 版本:利用priority_queueunordered_map,结合自定义结构体和比较运算符,实现高效的优先队列与图存储。

Prim 算法通过贪心策略平衡效率与正确性,在不同场景下可通过优化数据结构(如优先队列、斐波那契堆)提升性能。其在网络拓扑优化、资源分配等领域具有广泛应用,是图论算法中的基础且重要的工具。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MTXi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值