📅  最后修改于: 2023-12-03 15:25:50.623000             🧑  作者: Mango
最小生成树,是指一张给定无向图的一棵生成树,并且其边权和最小。生成树,就是一棵包含了给定图中全部n个顶点和只有n-1条边的树。
常用的有两种算法:Prim算法和Kruskal算法。
# Prim算法实现
def prim(graph):
v_num = len(graph) # 记录图中顶点个数
mst = [None] * v_num # 用于保存最小生成树的边
values = [999999] * v_num # 用于保存每个顶点到最小生成树的最短边的边权值
visited = [False] * v_num # 标记每个顶点是否已经被访问过
visited[0] = True # 从任意一个顶点开始都可以
for i in range(v_num - 1):
min_value = 999999 # 记录到最小生成树的最短边的权重值
for j in range(v_num):
if visited[j]: # 已访问过该顶点,则查找它的邻居顶点
for k in range(v_num):
if not visited[k] and graph[j][k] < values[k]: # 找到一条最短边
values[k] = graph[j][k]
mst[k] = (j, k, graph[j][k])
if graph[j][k] < min_value:
min_value = graph[j][k]
next_node = k
visited[next_node] = True
return mst
# Kruskal算法实现
def kruskal(graph):
v_num = len(graph) # 记录图中顶点个数
edges = []
for i in range(v_num):
for j in range(i, v_num): # 无向图,只需要遍历一半就可以了
if graph[i][j] != 0:
edges.append((i, j, graph[i][j]))
edges.sort(key=lambda x: x[2]) # 按边权值从小到大排序
parents = list(range(v_num)) # 用于记录每个顶点的祖先节点
mst = []
for edge in edges:
v1, v2, weight = edge
ancestor1, ancestor2 = find(parents, v1), find(parents, v2)
if ancestor1 != ancestor2: # 如果两个顶点不在同一个连通块中,则将它们连接起来
mst.append(edge)
parents[ancestor1] = ancestor2 # 将连接点的祖先节点更新
return mst
def find(parents, v):
"""
查找顶点v的祖先节点
"""
if parents[v] != v:
parents[v] = find(parents, parents[v])
return parents[v]
Prim算法和Kruskal算法在实现上略有不同,但它们的时间复杂度都为O(ElogE),其中 E 表示边的数量,因此速度上没有太大的差别。选择哪种算法更多取决于具体问题的特点和实现难易程度。