Python-最小生成树-Kruskal和Prim

Kruskal算法和Prim算法都是用于解决最小生成树问题的经典算法,它们的原理和实现略有不同,各有优劣势。

一、二者对比

(一)Kruskal算法

原理:Kruskal算法是一种贪心算法。它首先将所有的边按照权重从小到大进行排序,然后依次考虑每条边,如果该边连接的两个顶点不在同一个连通分量中(即加入该边不会形成环),则将该边加入最小生成树中。
优点:

  • 简单易懂,容易实现。
  • 适用于稀疏图,因为它按照边来考虑,而不是顶点。

缺点:

  • 实现时需要对边进行排序,时间复杂度为O(ElogE),其中E是边的数量。
  • 对于稠密图,算法的效率相对较低。

(二)Prim算法

原理:Prim算法也是一种贪心算法。它从一个初始顶点开始,每次选择与当前生成树相连的权重最小的边所连接的顶点加入生成树中,直到所有顶点都被加入。
优点:

  • 对于稠密图来说,Prim算法的效率更高,因为它按照顶点来考虑,而不是边。
  • 实现时可以使用优先队列(最小堆)来维护候选边,使得算法的时间复杂度为O(ElogV),其中V是顶点的数量。

缺点:

  • 实现稍微复杂一些,需要维护候选边的数据结构。

总结:

  • 如果是对于稀疏图(边的数量相对较少),可以优先选择Kruskal算法。
  • 如果是对于稠密图(边的数量较多),可以优先选择Prim算法。
  • 两者都是有效的最小生成树算法,选择哪种算法取决于具体的应用场景和问题特性。

 二、算法步骤

(一)Kruskal算法

1.初始化将图中的每个顶点视为一个独立的连通分量。
2.边的排序将图中的所有边按照权重从小到大进行排序。
3.遍历边按照排好序的边的顺序依次遍历。
4.边的选择对于每条边(u, v),如果顶点u和顶点v不在同一个连通分量中(即不会形成环),则选择该边加入最小生成树中。
5.连通分量合并:将顶点u和顶点v所在的连通分量合并为一个连通分量。
6.重复步骤4和步骤5,直到所有的顶点都在同一个连通分量中,即最小生成树构建完成。

(二)Prim算法

1.选择起始点:从图中任意一个顶点开始,作为最小生成树的起始点。
2.初始化集合:将起始点加入到一个集合(通常是一个优先队列或最小堆)中。
3.遍历集合中的顶点:重复以下步骤,直到集合包含所有顶点:
4.从集合中选择与当前最小生成树连接的边中权重最小的边。
5.将该边连接的顶点加入集合。
6.重复步骤3,直到最小生成树包含所有的顶点。

三、代码实现

 (一)Kruskal算法

class Kruskal:
    def __init__(self, vertices):
        self.vertices = vertices
        self.parent = {vertex: vertex for vertex in vertices}
        self.rank = {vertex: 0 for vertex in vertices}
        self.minimum_spanning_tree = []

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

    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)

        if root_u != root_v:
            if self.rank[root_u] > self.rank[root_v]:
                self.parent[root_v] = root_u
            elif self.rank[root_u] < self.rank[root_v]:
                self.parent[root_u] = root_v
            else:
                self.parent[root_v] = root_u
                self.rank[root_u] += 1

    def kruskal(self, edges):
        sorted_edges = sorted(edges, key=lambda edge: edge[2])

        for edge in sorted_edges:
            u, v, weight = edge
            if self.find(u) != self.find(v):
                self.minimum_spanning_tree.append(edge)
                self.union(u, v)

        return self.minimum_spanning_tree

# Example Usage:
vertices = ['A', 'B', 'C', 'D', 'E']
edges = [
    ('A', 'B', 4),
    ('A', 'C', 6),
    ('B', 'C', 2),
    ('B', 'D', 9),
    ('C', 'D', 7),
    ('C', 'E', 8),
    ('D', 'E', 3)
]

kruskal = Kruskal(vertices)
minimum_spanning_tree = kruskal.kruskal(edges)
print(minimum_spanning_tree)

(二)Prim算法 

import heapq

class Prim:
    def __init__(self, vertices):
        self.vertices = vertices
        self.adjacency_list = {vertex: [] for vertex in vertices}
        self.minimum_spanning_tree = []

    def add_edge(self, u, v, weight):
        """添加边到邻接列表"""
        self.adjacency_list[u].append((v, weight))
        self.adjacency_list[v].append((u, weight))

    def prim(self, start):
        """Prim算法实现"""
        visited = set()
        min_heap = [(0, start)]  # 使用堆存储候选边 (weight, vertex)
        while min_heap:
            weight, current_vertex = heapq.heappop(min_heap)
            if current_vertex not in visited:
                visited.add(current_vertex)
                for neighbor, edge_weight in self.adjacency_list[current_vertex]:
                    if neighbor not in visited:
                        heapq.heappush(min_heap, (edge_weight, neighbor))
                if len(self.minimum_spanning_tree) < len(self.vertices) - 1:
                    # 添加到最小生成树
                    self.minimum_spanning_tree.append((current_vertex, neighbor, weight))
        return self.minimum_spanning_tree

# 示例用法:
vertices = ['A', 'B', 'C', 'D', 'E']
prim = Prim(vertices)
prim.add_edge('A', 'B', 4)
prim.add_edge('A', 'C', 6)
prim.add_edge('B', 'C', 2)
prim.add_edge('B', 'D', 9)
prim.add_edge('C', 'D', 7)
prim.add_edge('C', 'E', 8)
prim.add_edge('D', 'E', 3)

minimum_spanning_tree = prim.prim('A')
print(minimum_spanning_tree)

 

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值