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

对于图求最小生成树


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 vertex
	e = []         # edge(i,j) list
	waiting_edge = defaultdict(list)       # len:edge(i,j) list

	# init
	v.add(0)
	for j, weight in enumerate(graph[0]):
		if weight:
			waiting_edge[weight].append((0,j))

	# loop1
	while waiting_edge:
		find = None
		# loop2
		while waiting_edge and find is None:
			min_weight = min(waiting_edge)
			del_list = []
			# loop3
			for (i_i, i_j) in waiting_edge[min_weight]:
				del_list.append((i_i, i_j))
				if i_j not in v:
					find = i_j
					e.append((i_i, i_j))
					break
			# loop4
			for 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_edge
			v.add(find)
			# loop5
			for 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 = 0xffffff
chosen_int = max_int - 1
def prim_pro(graph):
	edge_info = [(weight, 0) for weight in graph[0]]
	edge_info[0] = (chosen_int, 0)
	e = []           # edge(i,j) list

	for i in xrange(1, len(graph)):
		# find min
		min_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])
		# loose
		for 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)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值