对于图寻找最小生成树
顶点v使用并查集,初始状态下所有顶点都是一个集合。
Kruskal算法描述:
取最短的边,比较是否两个顶点都在同一集合内:如果都在,则舍弃
初始化时,v长这样
v = [i for i in xrange(0, length)]
并(i, j)的操作就是合并两个集合的跟:
r_i = find_root(v, i)
r_j = find_root(v, j)
v[r_j] = r_i
查找操作中,我增加了路径压缩,使得效率能提升
def find_root(d_set, key):
if d_set[key] == key:
return key
# flat
root = key
cur_key = key
while d_set[cur_key] != cur_key:
root = d_set[cur_key]
cur_key = root
d_set[key] = root
return root
最后是kruskal的算法了:
def kruskal(graph):
# only traverse half of the graph
# because graph is undirected
length = len(graph)
# init
edge_info = [] # (weight, i, j) list
for i in xrange(0, len(graph)):
for j in xrange(0, i):
if graph[i][j]:
edge_info.append((graph[i][j], i, j))
edge_info.sort()
v = [i for i in xrange(0, length)] # disjoint set
e = []
for (_, i, j) in edge_info:
r_i = find_root(v, i)
r_j = find_root(v, j)
if r_i == r_j:
continue
# union
v[r_j] = r_i
e.append((i, j))
return e
驱动
graph = [[0, 7, 9, 0, 0, 14],
[7, 0, 10, 15, 0, 0],
[9, 10, 0, 11, 0, 2],
[0, 15, 11, 0, 6, 0],
[0, 0, 0, 6, 0, 9],
[14, 0, 2, 0, 9, 0]]
print kruskal(graph)
排序需要O(Edge * log(Edge)),查找时是O(Edge * 接近常数的数)
最终时间复杂度为O(Edge * log(Edge))