Skip to content

Commit 5630e36

Browse files
committed
最小生成树Prim算法
1 parent 06caa49 commit 5630e36

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

prim_algorithm.md

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#问题
2+
3+
无向图最小生成树的Prim算法
4+
5+
#思路说明
6+
7+
假设点A,B,C,D,E,F,两点之间有连线的,以及它们的距离分别是:(A-B:7);(A-D:5);(B-C:8);(B-D:9);(B-E:7);(C-E:5);(D-E:15);(D-F:6);(E-F:8);(E-G:9);(F-G:11)
8+
9+
关于Prim算法的计算过程,参与维基百科的词条:[普里姆算法](http://zh.wikipedia.org/wiki/%E6%99%AE%E6%9E%97%E5%A7%86%E7%AE%97%E6%B3%95)
10+
11+
将上述点与点关系以及两点之间距离(边长,有的文献中称之为权重)写成矩阵形式(在list中,每两个点及其之间的距离组成一个tuple)
12+
13+
edges = [ ("A", "B", 7),
14+
("A", "D", 5),
15+
("B", "C", 8),
16+
("B", "D", 9),
17+
("B", "E", 7),
18+
("C", "E", 5),
19+
("D", "E", 15),
20+
("D", "F", 6),
21+
("E", "F", 8),
22+
("E", "G", 9),
23+
("F", "G", 11)
24+
]
25+
26+
在下面的解决方法中,要计算出与已经选出的若干个点有相邻关系的点中,相应边长最短的点。这本质上是排序之后取出最小的,因为这种排序是动态的,如果用sorted或者list.sort()之类的方法对list排序,一则速度慢(python中的sort方法对大数据时不是很快),二则代码也长了。幸好python提供了一个非常好用的模块:heapq。这个模块是堆排序方法实现排序,并能够随时取出最小值。简化代码,更重要是提升了速度。
27+
28+
就用这个来解决Prim算法问题了。
29+
30+
#解决(Python)
31+
32+
#! /usr/bin/env python
33+
#coding:utf-8
34+
35+
from collections import defaultdict
36+
from heapq import *
37+
38+
def prim( vertexs, edges ):
39+
adjacent_vertex = defaultdict(list) #注意:defaultdict(list)必须以list做为变量,可以详细阅读:[collections.defaultdict](https://docs.python.org/2/library/collections.html#collections.defaultdict)
40+
41+
for v1,v2,length in edges:
42+
adjacent_vertex[v1].append((length, v1, v2))
43+
adjacent_vertex[v2].append((length, v2, v1))
44+
45+
"""
46+
经过上述操作,将edges列表中各项归类成以某点为dictionary的key,其value则是其相邻的点以及边长。如下:
47+
48+
defaultdict(<type 'list'>, {'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')]})
49+
50+
"""
51+
52+
mst = [] #存储最小生成树结果
53+
54+
chosed = set(vertexs[0])
55+
56+
"""
57+
vertexs是顶点列表,vertexs = list("ABCDEFG")===>vertexs=['A', 'B', 'C', 'D', 'E', 'F', 'G']
58+
>> chosed=set(vertexs[0])
59+
>> chosed
60+
set(['A'])
61+
也就是,首先选一个点(这个点是可以任意选的),以这个点为起点,找其相邻点,以及最短边长。
62+
63+
"""
64+
65+
#得到adjacent_vertexs_edges中顶点是'A'(nodes[0]='A')的相邻点list,即adjacent_vertexs['A']=[(7,'A','B'),(5,'A','D')]
66+
67+
adjacent_vertexs_edges = adjacent_vertex[vertexs[0]]
68+
69+
#将usable_edges加入到堆中,并能够实现用heappop从其中动态取出最小值。关于heapq模块功能,参考python官方文档
70+
71+
heapify(adjacent_vertexs_edges)
72+
73+
while adjacent_vertexs_edges:
74+
#得到某个定点(做为adjacent_vertexs_edges的键)与相邻点距离(相邻点和边长/距离做为该键的值)最小值,并同时从堆中清除。
75+
w, v1, v2 = heappop(adjacent_vertexs_edges)
76+
if v2 not in chosed:
77+
78+
#在used中有第一选定的点'A',上面得到了距离A点最近的点'D',举例是5。将'd'追加到used中
79+
chosed.add(v2)
80+
81+
mst.append((v1,v2,w)) #将v1,v2,w,第一次循环就是('A','D',5) append into mst
82+
83+
#再找与d相邻的点,如果没有在heap中,则应用heappush压入堆内,以加入排序行列
84+
85+
for next_vertex in adjacent_vertex[v2]:
86+
if next_vertex[2] not in chosed:
87+
heappush( adjacent_vertexs_edges,next_vertex)
88+
return mst
89+
90+
91+
#test
92+
vertexs = list("ABCDEFG")
93+
edges = [ ("A", "B", 7), ("A", "D", 5),
94+
("B", "C", 8), ("B", "D", 9),
95+
("B", "E", 7), ("C", "E", 5),
96+
("D", "E", 15), ("D", "F", 6),
97+
("E", "F", 8), ("E", "G", 9),
98+
("F", "G", 11)]
99+
100+
print "edges:",edges
101+
print "prim:", prim( vertexs, edges )
102+
103+
##运行结果
104+
105+
edges: [('A', 'B', 7), ('A', 'D', 5), ('B', 'C', 8), ('B', 'D', 9), ('B', 'E', 7), ('C', 'E', 5), ('D', 'E', 15), ('D', 'F', 6), ('E', 'F', 8), ('E', 'G', 9), ('F', 'G', 11)]
106+
prim: [('A', 'D', 5), ('D', 'F', 6), ('A', 'B', 7), ('B', 'E', 7), ('E', 'C', 5), ('E', 'G', 9)]
107+
108+

prim_algorithm.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#! /usr/bin/env python
2+
#coding:utf-8
3+
4+
5+
from collections import defaultdict
6+
from heapq import *
7+
8+
9+
def prim( vertexs, edges ):
10+
adjacent_vertex = defaultdict(list)
11+
for v1,v2,length in edges:
12+
adjacent_vertex[v1].append((length, v1, v2))
13+
adjacent_vertex[v2].append((length, v2, v1))
14+
15+
mst = []
16+
chosed = set(vertexs[0])
17+
18+
adjacent_vertexs_edges = adjacent_vertex[vertexs[0]]
19+
20+
heapify(adjacent_vertexs_edges)
21+
22+
while adjacent_vertexs_edges:
23+
w, v1, v2 = heappop(adjacent_vertexs_edges)
24+
if v2 not in chosed:
25+
chosed.add(v2)
26+
mst.append((v1,v2,w))
27+
for next_vertex in adjacent_vertex[v2]:
28+
if next_vertex[2] not in chosed:
29+
heappush( adjacent_vertexs_edges,next_vertex)
30+
31+
return mst
32+
33+
34+
#test
35+
vertexs = list("ABCDEFG")
36+
edges = [ ("A", "B", 7), ("A", "D", 5),
37+
("B", "C", 8), ("B", "D", 9),
38+
("B", "E", 7), ("C", "E", 5),
39+
("D", "E", 15), ("D", "F", 6),
40+
("E", "F", 8), ("E", "G", 9),
41+
("F", "G", 11)]
42+
43+
print "edges:",edges
44+
print "prim:", prim( vertexs, edges )

0 commit comments

Comments
 (0)