|
| 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 | + |
0 commit comments