构造最小生成树算法的一个关键是需要把点集分割成两部分,这两不得点之间不存在连接,然后从当前边的集合中找到让两个集合之间的点产生连接,而且数值是最小的边,之后就是一直重复这个操作,直到所有的点都被连接为止。
而prim算法就可以构造最小生成树,它的基本思路就是维持两个点集S和V-S,其中S中的点相互连通,也就是在集合S中,从任意一点触发都可以抵达集合中的其他点,而V-S中的点事零散点,也就是其中任何点都没有与其他点会成产生连接
添加图片注释,不超过 140 字(可选)
添加图片注释,不超过 140 字(可选)
添加图片注释,不超过 140 字(可选)
对于上图的两个集合,如何使用prim算法的想法来操作,也就是遍历所有的边,找到一条能够将左边节点和右边节点连接起来,而且数值最小的一条边。
如何快速的找到一条连接左右两个集合节点而且数值最小的边,这里就可以使用到堆排序,一开始左边集合S为空,右边集合包含所有节点,然后随机在节点中选择一个节点放置如左边的集合,然后将把放入左边集合的点有关的所有边加入到一个小堆中,根据小堆的性质,数值最小的边一定在堆的顶部,于是可以轻易的将这条边获取到,从这条边开始就可以找到第二个加入集合S的节点,然后把第二个节点所对应的边也加入到小堆中,于是连接左边集合中两个点和右边集合中的最小边又出现在堆的顶部,如此循环直到所有点都加入到左边集合为止。
使用python实现prim算法的代码如下:
import heapq def get_edges_by_vertex(v):
#获得该节点对应的所有边
edges = [] for edge in E: v1 v2 = edge.get_points()
if v1 == v or v2 == v:
edges.append(edge)
return edges
vertex_count = len(vertexes)
edge_heap = []
v = vertexes.pop() #随机选择一个节点加入集合S
v.selected = True #给节点对象增加一个标志说明它已经被加入到集合S
S = []
S.append(v)
edge_order = 0
edges = get_edges_by_vertex(v) #获取该节点对应的所有边
for e in edges: #将加入集合S的点对应的边插入堆
heapq.heappush(edge_heap (e.get_edge_value() edge_order e))
edge_order += 1 cost = 0
while len(S) < vertex_count:
e = heapq.heappop(edge_heap)[2] #从堆上取得连接集合S和V-S且数值最小的边
v1 v2 = e.get_points()
if hasattr(v1 'selected') is True and hasattr(v2 'selected') is True:
#该边两个节点都已经属于集合S
continue
print(\Add new edge: \ end = '')
e.print_edge()
cost += e.get_edge_value()
v = v1
if hasattr(v1 'selected') is True:
#选出还没有加入集合S的那个点 v = v2 v.selected = True S.append(v)
edges = get_edges_by_vertex(v)
for e in edges:
v1 v2 = e.get_points()
if hasattr(v1 'selected') is False or hasattr(v2 'selected') is False:
#确保加入堆的边是连接连接两个集合的边而不是连接S内部节点的边
heapq.heappush(edge_heap (e.get_edge_value() edge_order e))
edge_order += 1
print('mini spanning tree cost : {0}'.format(cost))