Prim算法(Python实现)

Prim算法是图论中的一种算法,可在加权连通图里搜索最小生成树

算法描述

  1. 输入:一个加权连通图,顶点集合为V,边集合为E
  2. 初始化:Vnew={x},其中x是V中任一节点,作为起始点,Enew={}
  3. 在E中选择权重最小的边(u,v),其中u为集合Vnew中的元素,而v则是V中没有加入Vnew的顶点(如果权重相同就任选一个)
  4. 将v加入集合Vnew中,将(u,v)加入集合Enew中
  5. 重复步骤3-4,知道Vnew=V
  6. 输出:使用Enew和Vnew描述得到的最小生成树

对于使用堆和邻接表表示最小权边和图的情况,时间复杂度为 O ( ( ∣ V ∣ + ∣ E ∣ ) log ⁡ ∣ V ∣ ) = O ( ∣ E ∣ log ⁡ ∣ V ∣ ) {\displaystyle O((|V|+|E|)\log |V|)=O(|E|\log |V|)} O((V+E)logV)=O(ElogV)

算法示例

在这里插入图片描述
在这里插入图片描述

代码实现

对于图:
在这里插入图片描述

from collections import defaultdict
from heapq import *

def prim(vertexs, edges,start='D'):
    adjacent_dict = defaultdict(list) # 注意:defaultdict(list)必须以list做为变量
    for weight,v1, v2 in edges:
        adjacent_dict[v1].append((weight, v1, v2))
        adjacent_dict[v2].append((weight, v2, v1))
    '''
    经过上述操作,将图转化为以下邻接表形式:
    {'A': [(7, 'A', 'B'), (5, 'A', 'D')], 
     'C': [(8, 'C', 'B'), (5, 'C', 'E')], 
     'B': [(7, 'B', 'A'), (8, 'B', 'C'), (9, 'B', 'D'), (7, 'B', 'E')], 
     'E': [(7, 'E', 'B'), (5, 'E', 'C'), (15, 'E', 'D'), (8, 'E', 'F'), (9, 'E', 'G')], 
     'D': [(5, 'D', 'A'), (9, 'D', 'B'), (15, 'D', 'E'), (6, 'D', 'F')], 
     'G': [(9, 'G', 'E'), (11, 'G', 'F')], 
     'F': [(6, 'F', 'D'), (8, 'F', 'E'), (11, 'F', 'G')]})
    '''
    minu_tree = []  # 存储最小生成树结果
    visited = [start] # 存储访问过的顶点,注意指定起始点
    adjacent_vertexs_edges = adjacent_dict[start]
    heapify(adjacent_vertexs_edges) # 转化为小顶堆,便于找到权重最小的边
    while adjacent_vertexs_edges:
        weight, v1, v2 = heappop(adjacent_vertexs_edges) # 权重最小的边,并同时从堆中删除。 
        if v2 not in visited:
            visited.append(v2)  # 在used中有第一选定的点'A',上面得到了距离A点最近的点'D',举例是5。将'd'追加到used中
            minu_tree.append((weight, v1, v2))
            # 再找与d相邻的点,如果没有在heap中,则应用heappush压入堆内,以加入排序行列
            for next_edge in adjacent_dict[v2]: # 找到v2相邻的边
                if next_edge[2] not in visited: # 如果v2还未被访问过,就加入堆中
                    heappush(adjacent_vertexs_edges, next_edge)
    return minu_tree

vertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
edges = [(7, 'A', 'B'),
         (5, 'A', 'D'),
         (8, 'B', 'C'),
         (9, 'B', 'D'),
         (7, 'B', 'E'),
         (5, 'C', 'E'),
         (15, 'D', 'E'),
         (6, 'D', 'F'),
         (8, 'E', 'F'),
         (9, 'E', 'G'),
         (11, 'F', 'G'),
         ]
print(prim(vertices, edges ,start='D'))

输出为:

[(5, 'D', 'A'), (6, 'D', 'F'), (7, 'A', 'B'), (7, 'B', 'E'), (5, 'E', 'C'), (9, 'E', 'G')]
  • 8
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值