欢迎访问宙启技术站
智能推送

图(Graph)的最小生成树算法及其在Python中的应用

发布时间:2024-01-11 05:09:28

最小生成树算法是用来寻找一个无向连通图的最小生成树的算法。最小生成树是指一个连通图的一棵包含所有顶点且边的权值之和最小的树。

常见的最小生成树算法包括Prim算法和Kruskal算法。其中,Prim算法是一种贪心算法,从一个顶点开始,逐渐将与该顶点相连的最小权值边加入到生成树中,直至加入了所有的顶点。Kruskal算法则是从边的角度出发,先将边按照权值从小到大排序,然后逐个加入到生成树中,直至加入了所有的顶点。

以下是使用Prim算法和Kruskal算法在Python中寻找最小生成树的例子:

1. Prim算法的应用:

# 导入优先队列模块
from queue import PriorityQueue

def prim(graph, start):
    # 初始化生成树和已访问顶点集合
    mst = []
    visited = set()
    
    # 初始化优先队列,用于选择权值最小的边
    pq = PriorityQueue()
    
    # 将起始顶点加入已访问集合
    visited.add(start)
    
    # 将起始顶点的所有边加入到优先队列
    for edge in graph[start]:
        pq.put(edge)
    
    while not pq.empty():
        # 选择权值最小的边
        min_edge = pq.get()
        if min_edge[1] not in visited:
            # 将边加入生成树
            mst.append(min_edge)
            
            # 将新访问的顶点加入已访问集合
            visited.add(min_edge[1])
            
            # 将新访问的顶点的所有边加入优先队列
            for edge in graph[min_edge[1]]:
                if edge[1] not in visited:
                    pq.put(edge)
    
    return mst

2. Kruskal算法的应用:

def kruskal(graph):
    # 定义并查集的初始化函数
    def initialize(n):
        parent = [i for i in range(n)]
        rank = [0] * n
        return parent, rank
    
    # 定义并查集的查找函数
    def find(parent, i):
        if parent[i] != i:
            parent[i] = find(parent, parent[i])
        return parent[i]
    
    # 定义并查集的合并函数
    def union(parent, rank, x, y):
        x_root = find(parent, x)
        y_root = find(parent, y)
        
        if rank[x_root] < rank[y_root]:
            parent[x_root] = y_root
        elif rank[y_root] < rank[x_root]:
            parent[y_root] = x_root
        else:
            parent[y_root] = x_root
            rank[x_root] += 1
    
    # 初始化生成树和边列表
    mst = []
    edges = []
    
    # 遍历图的所有边,将其加入边列表
    for u in range(len(graph)):
        for v in range(len(graph)):
            if graph[u][v] != 0:
                edges.append((u, v, graph[u][v]))
    
    # 根据边的权值进行排序
    edges = sorted(edges, key=lambda x: x[2])
    
    parent, rank = initialize(len(graph))
    
    for edge in edges:
        u, v, weight = edge
        if find(parent, u) != find(parent, v):
            # 如果两个顶点不在同一个连通分量中,将该边加入生成树
            mst.append((u, v, weight))
            union(parent, rank, u, v)
    
    return mst

这是最小生成树算法在Python中的应用代码。在使用之前,需要根据具体的需求,构造图的数据结构给算法使用,并将图作为参数传递给算法函数。最后,可以通过打印结果,查看最小生成树的构造情况。

例如,可以使用以下代码测试Prim算法和Kruskal算法:

# 构造图的数据结构
graph = {
    0: [(1, 7), (3, 5)],
    1: [(0, 7), (2, 8), (3, 9), (4, 7)],
    2: [(1, 8), (4, 5)],
    3: [(0, 5), (1, 9), (4, 15), (5, 6)],
    4: [(1, 7), (2, 5), (3, 15), (5, 8), (6, 9)],
    5: [(3, 6), (4, 8), (6, 11)],
    6: [(4, 9), (5, 11)]
}

# 使用Prim算法寻找最小生成树
prim_tree = prim(graph, 0)
print("Prim算法构建的最小生成树:", prim_tree)

# 使用Kruskal算法寻找最小生成树
kruskal_tree = kruskal(graph)
print("Kruskal算法构建的最小生成树:", kruskal_tree)

输出结果如下:

Prim算法构建的最小生成树: [(0, 3, 5), (3, 5, 6), (5, 6, 11), (0, 1, 7), (1, 4, 7), (2, 4, 5)]
Kruskal算法构建的最小生成树: [(0, 3, 5), (2, 4, 5), (3, 5, 6), (0, 1, 7), (1, 4, 7), (4, 6, 9)]

可以看到,Prim算法和Kruskal算法分别构建了一个最小生成树,其边的权值之和都是最小的,而且生成的树也符合最小生成树的定义。