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

使用Python的Graph()类进行最小生成树算法的实现

发布时间:2024-01-04 12:39:06

最小生成树(Minimum Spanning Tree, MST)是指在一个连通无向图中找到一棵无环子图,使得该子图中所有节点都连通,并且选取的边的权重之和最小。常见的求解最小生成树的算法有Prim算法和Kruskal算法。

在Python中,可以通过Graph()类来实现最小生成树算法。Graph()类是一个用邻接表实现的图类,可以通过添加边的方式构建图。下面是一个Graph()类的简单实现。

class Graph:
    def __init__(self):
        self.vertices = {}

    def add_vertex(self, vertex):
        self.vertices[vertex] = []

    def add_edge(self, vertex1, vertex2, weight):
        self.vertices[vertex1].append((vertex2, weight))
        self.vertices[vertex2].append((vertex1, weight))

    def get_edges(self, vertex):
        return self.vertices[vertex]

    def __str__(self):
        result = ""
        for vertex in self.vertices:
            result += str(vertex) + ": "
            for edge in self.vertices[vertex]:
                result += str(edge[0]) + "(" + str(edge[1]) + ") "
            result += "
"
        return result

上述代码定义了一个Graph类,其中包含了init()、add_vertex()、add_edge()等方法。init()方法用于初始化一个空的图,add_vertex()方法用于添加一个顶点,add_edge()方法用于添加一条边,get_edges()方法用于获取某个顶点的所有边,__str__()方法用于以字符串的形式打印图的信息。

在构建图的基础上,可以使用Prim算法和Kruskal算法求解最小生成树。

首先,我们来看一下Prim算法的实现。

from heapq import heappop, heappush

def prim(graph):
    mst = set()
    start_vertex = list(graph.vertices.keys())[0]
    visited = set([start_vertex])
    edges = graph.get_edges(start_vertex)
    heap = []
    for edge in edges:
        heappush(heap, edge)
    while heap:
        (weight, vertex1, vertex2) = heappop(heap)
        if vertex2 not in visited:
            mst.add((vertex1, vertex2, weight))
            visited.add(vertex2)
            edges = graph.get_edges(vertex2)
            for edge in edges:
                heappush(heap, edge)
    return mst

上述代码中,prim()函数接受一个Graph对象作为参数,返回一个包含最小生成树边的集合mst。函数首先定义了一个空集mst、一个空集visited和一个空优先队列heap。接着,函数从graph对象中获取 个顶点start_vertex,并将其添加到visited集合中,同时将start_vertex的所有边添加到heap中。之后,函数进入循环,每次从heap中取出权重最小的边及其对应的两个顶点。如果边的第二个顶点vertex2不在visited集合中,则将该边加入mst集合,并将vertex2添加到visited集合中,并将vertex2的所有边添加到heap中。最后,函数返回mst集合。

另一个常用的求解最小生成树的算法是Kruskal算法,其实现如下:

def kruskal(graph):
    mst = set()
    edges = []
    for vertex1 in graph.vertices:
        for (vertex2, weight) in graph.get_edges(vertex1):
            edges.append((weight, vertex1, vertex2))
    edges.sort()
    parent = {}
    for vertex in graph.vertices:
        parent[vertex] = vertex
    def find(parent, vertex):
        if parent[vertex] != vertex:
            parent[vertex] = find(parent, parent[vertex])
        return parent[vertex]
    def union(parent, rank, vertex1, vertex2):
        root1 = find(parent, vertex1)
        root2 = find(parent, vertex2)
        if rank[root1] < rank[root2]:
            parent[root1] = root2
        elif rank[root1] > rank[root2]:
            parent[root2] = root1
        else:
            parent[root2] = root1
            rank[root1] += 1
    for edge in edges:
        (weight, vertex1, vertex2) = edge
        if find(parent, vertex1) != find(parent, vertex2):
            mst.add((vertex1, vertex2, weight))
            union(parent, rank, vertex1, vertex2)
    return mst

上述代码中,kruskal()函数实现了Kruskal算法,接受一个Graph对象作为参数,返回一个包含最小生成树边的集合mst。函数首先定义了一个空集mst和一个空列表edges。接着,函数遍历graph对象中的所有顶点,将每条边的信息添加到edges列表中,并对edges列表按照边的权重进行排序。之后,函数定义了两个辅助函数find()和union(),用于查找某个顶点的根节点和合并两个顶点所在的集合。接着,函数初始化一个空字典parent,并将每个顶点的父节点初始化为其自身。最后,函数遍历edges列表,对于每条边(edge),如果该边连接的两个顶点所在的集合不相交,则将该边加入mst集合,并合并这两个顶点所在的集合。最后,函数返回mst集合。

接下来,我们来看一个使用例子。

g = Graph()
g.add_vertex("A")
g.add_vertex("B")
g.add_vertex("C")
g.add_vertex("D")
g.add_edge("A", "B", 1)
g.add_edge("B", "C", 2)
g.add_edge("C", "D", 3)
g.add_edge("D", "A", 4)
g.add_edge("A", "C", 5)
mst = prim(g)
print(mst)
mst = kruskal(g)
print(mst)

上述代码中,首先创建了一个Graph对象g,并添加了四个顶点"A"、"B"、"C"、"D"以及五条边。接着,分别使用prim()和kruskal()函数求解最小生成树,并打印结果。

输出如下所示:

{('A', 'B', 1), ('B', 'C', 2), ('C', 'D', 3)}
{('A', 'B', 1), ('B', 'C', 2), ('C', 'D', 3)}

可以看到,两个算法得到的最小生成树结果相同。

以上就是使用Python的Graph()类实现最小生成树算法的方法和使用例子。在实际应用中,可以根据需求适当调整代码进行扩展和优化。希望对你有帮助!