最小生成树----Prim算法+loose操作

来源:互联网 发布:韩国人吃不起肉 知乎 编辑:程序博客网 时间:2024/05/22 17:35

对于图求最小生成树


Prim算法中,有两个顶点集合:v和u,一个边的集合:e

v:e中的顶点

u:all - v

e:存放所有已选的边

算法描述:

从所有边中取最短的边e(i,j),i属于v,j属于u。

将e(i,j)放入e中

将j从u中放入v中

在写算法的过程中,增加了数据结构waiting_edge,存放所有(v,u)点对

def prim(graph):v = set()      # chosen vertexe = []         # edge(i,j) listwaiting_edge = defaultdict(list)       # len:edge(i,j) list# initv.add(0)for j, weight in enumerate(graph[0]):if weight:waiting_edge[weight].append((0,j))# loop1while waiting_edge:find = None# loop2while waiting_edge and find is None:min_weight = min(waiting_edge)del_list = []# loop3for (i_i, i_j) in waiting_edge[min_weight]:del_list.append((i_i, i_j))if i_j not in v:find = i_je.append((i_i, i_j))break# loop4for item in del_list:waiting_edge[min_weight].remove(item)if not waiting_edge[min_weight]:del waiting_edge[min_weight]if find:# add i to v# expand waiting_edgev.add(find)# loop5for j, weight in enumerate(graph[find]):if weight and j not in v:waiting_edge[weight].append((find,j))return e

这是最直观的解法,直接翻译了上面的算法。

loop1至多遍历Vertex次,也就是说,最小生成树不可能含有多于Vertex个点

loop2先不管,先看loop3和loop4。它们循环的次数相同,至多循环Edge次。注意loop3中有一个查询set的语句,意味着log(Vertex)的时间开销。loop4中有remove的操作,最坏情况下O(Edge)的开销。

loop2里有一个min操作,根据waiting_edge的数据结构,可能为O(Edge)[hash]次比较,也可能为O(1)[堆]。

loop2里有跟新waiting_edge的操作,可能为O(1)[hash]也可能为O(log(Edge))。

loop5可能遍历Vertex次,如果是用图的数据结构的话总共遍历Edge次

可以看出还是很耗时的。


下面来挖掘隐含条件:

1. 不需要存储所有的边:生成树只会有Vertex-1条边

2. 如果i和j都在v中,且k在u中,那么只需要存储e(i,k)和e(j,k)中较短的边。这里有一个loose操作(参见Dijkastra算法)。

所以需要一个数据结构edge_info

edge_info[u中的节点] = (较短的边长, v中的节点)

edge_info[v中的节点]=无意义的数,这里我用chosen_int表示

max_int = 0xffffffchosen_int = max_int - 1def prim_pro(graph):edge_info = [(weight, 0) for weight in graph[0]]edge_info[0] = (chosen_int, 0)e = []           # edge(i,j) listfor i in xrange(1, len(graph)):# find minmin_info = min(edge_info)# put k in v, reset min_info[k]k = edge_info.index(min_info)e.append((min_info[1], k))edge_info[k] = (chosen_int, min_info[1])# loosefor j, weight in enumerate(graph[k]):if weight < edge_info[j][0] and edge_info[j][0] != chosen_int:edge_info[j] = (weight, k)return e
带上隐含条件后的代码就简单多了

耗时为O(Vertex^2)