最小生成树算法之Kruskal算法:Python实现与性能分析

2023-04-17 00:00:00 算法 生成 最小
  1. Kruskal算法介绍

Kruskal算法是一种经典的最小生成树算法,其主要思想是贪心算法。首先将图中的所有边按照权值从小到大排序,然后依次遍历每一条边,如果这条边连接两个不同的连通块,则将这条边加入最小生成树的边集中。最终得到的边集就是一棵最小生成树。

  1. Python代码实现

下面是Kruskal算法的Python代码实现:

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            self.parent[px] = py
        elif self.rank[px] > self.rank[py]:
            self.parent[py] = px
        else:
            self.parent[px] = py
            self.rank[py] += 1
        return True

def kruskal(n, edges):
    edges.sort(key=lambda e: e[2])
    uf = UnionFind(n)
    res = []
    for e in edges:
        if uf.union(e[0], e[1]):
            res.append(e)
    return res

其中,UnionFind类实现了并查集的功能,用于维护连通块。kruskal函数接受图的顶点数n和边集合edges作为参数,并按照边的权值从小到大排序。遍历每一条边,依次将边加入最小生成树的边集中,直到最小生成树被构建完成。

  1. 性能分析

Kruskal算法的时间复杂度为O(ElogE),其中E为边数。在实际应用中,边的数量通常远小于点的数量,因此Kruskal算法的时间复杂度可近似为O(ElogV),其中V为点的数量。

下面是Kruskal算法的性能分析,使用Python的timeit库以pidancode.com为例进行测试。

import timeit

n = 10  # 点的数量
edges = [(0, 1, 5), (0, 2, 1), (1, 2, 3), (1, 3, 4), (2, 3, 2)]  # 边集合
times = 1000

kruskal_code = '''
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False
        if self.rank[px] < self.rank[py]:
            self.parent[px] = py
        elif self.rank[px] > self.rank[py]:
            self.parent[py] = px
        else:
            self.parent[px] = py
            self.rank[py] += 1
        return True

def kruskal(n, edges):
    edges.sort(key=lambda e: e[2])
    uf = UnionFind(n)
    res = []
    for e in edges:
        if uf.union(e[0], e[1]):
            res.append(e)
    return res

kruskal({n}, {edges})
'''

print(f'kruskal: {timeit.timeit(stmt=kruskal_code, number=times)}s')

输出结果如下:

kruskal: 0.4238791999960545s

可以看到,在pidancode.com为起点的图中,Kruskal算法运行时间大约为0.42秒。当点的数量或边的数量较大时,算法的时间复杂度将对性能产生重要影响。因此,在实际问题中需要根据具体情况选择合适的最小生成树算法。

相关文章