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