最小生成树:Prim算法实现


title: ‘最小生成树:Prim算法实现’
date: 2019-09-03 19:32:57
tags: python,数据结构
categories: 计算机理论

Prim算法

算法原理及算法流程

原理

根据(MST性质:网络G必有一颗最小生成树),具体证明不再赘述,大概思想就是假设你现有一个图的集合G,从G中的一个顶点出发,不断的选择最短的一条连接边,扩充到已选边集N中,直至N包含了图G中的所有顶点。

构造过程举例

假设现在有这样一颗图

第一次构造

V1的邻接节点全部入队。并且由于该队列是优先级队列,会按照权重排序

v1,v3,1
v1,v4,5
v1,v2,6

队首出队,构造边,将该边加入到N集

此时N集中就有了一条边了

1
v1
V3

V3除了N集中的结点的邻接节点入队,优先队列会按照权重进行排序

v3,v2,5
v3,v4,5
v3,v5,6
v3,v6,4
v1,v4,5
v1,v2,6
第二次构造

队首出队,构造边,将该边加入到N集

此时N集有两条边了

1
4
v1
V3
V6

V6的除N集中已有的邻接节点入队,

v6,v4,2
V6,V5,6
v3,v2,5
v3,v4,5
v3,v5,6
v1,v4,5
v1,v2,6
第三次构造

队首出队,构造边,将该边<6,4>加入到N集

此时的N集就有三条边了

1
4
2
v1
V3
V6
V4

V4的除N集中已有的邻接节点入队,发现v4的邻接顶点都在N集中了,所以没有顶点入队

V6,V5,6
v3,v2,5
v3,v4,5
v3,v5,6
v1,v4,5
v1,v2,6
第四次构造

队首<v1,v4>出队,构造边,将该边<v1,v4>加入到N集,注意此时由于<v1,v4>加入N集中会构成连通,所以跳过本次构造边

1
4
2
5
v1
V3
V6
V4

所以,当前N集中的边还是和原来一样,如下图:

1
4
2
v1
V3
V6
V4

V4的除N集中已有的邻接节点入队,发现v4的邻接顶点都在N集中了,所以没有顶点入队

V6,V5,6
v3,v2,5
v3,v4,5
v3,v5,6
v1,v2,6
第五次构造

队首<v3,v2>出队,构造边,将该边加入到N集中。

此时N集就有五条边了

1
4
2
5
v1
V3
V6
V4
V2

V2的除N集中已有的邻接节点入队

V6,V5,6
v3,v2,5
v3,v4,5
v3,v5,6
v1,v2,6
V2,V5,3
第六次构造

队首<v2,v5>出队,构造边,加入边到N集中。此时N集中有5条边。由于总共就6个顶点,当构成最小生成树的时候边只能是5条,你如果在加一条边就连通了,所以prim构造生成树结束

1
4
2
5
3
v1
V3
V6
V4
V2
V5
最终结果
1
4
2
5
3
v1
V3
V6
V4
V2
V5

算法实现

   # prim算法,最小生成树,前提该图必须是连通网
    def prim(self, start):
        if not self._invalid(start):
            raise GraphError("不存在" + start + "这样的顶点")
        result = GraphAL({})
        edgeCount = 0
        pqueue = []  # 优先级队列,候选列表
        # 初始化优先级队列
        for node in self._graph[start]:
            heapq.heappush(pqueue, (self._graph[start][node], start, node))
            pass
        while edgeCount < self.get_vertexNum() - 1 and not pqueue.__len__() == 0:
            # 出队
            pair = heapq.heappop(pqueue)
            distance = pair[0]
            start = pair[1]
            end = pair[2]
            # 判断是否有该顶点,如果没有就要加入
            if start not in result._graph:
                result.add_vertex(start)
            if end not in result._graph:
                result.add_vertex(end)
            # 如果当前点与下一节点未建立边,则尝试建立边
            # 方式是检查下一节点是否在result中,如果有则说明这个节点已经建立过边了,再建立边的话会可能会形成连通,因此直接舍弃该边的建立
            if end not in result._graph[start]:
                # 如果下一个节点如果未被其他节点连接则result._graph[end]返回false,开始构造边,
                # 如果下一个节点已经被连接了,则result._graph[end]返回true,舍弃该边的建立
                if not result._graph[end]:
                    result.add_edge(start, end, distance)
                    edgeCount += 1
                    pass
            start = end
            # 子节点入队
            for node in self._graph[start]:
                if node not in result._graph:
                    heapq.heappush(pqueue, (self._graph[start][node], start, node))
            pass
        return result

测试

20190830224239

与刚才流程构造的结果一致

1
4
2
5
3
v1
V3
V6
V4
V2
V5

猜你喜欢

转载自blog.csdn.net/weixin_41154636/article/details/100526938