幾種常見的最小生成樹算法以及代碼實(shí)現(xiàn)注釋
以下是幾種常見的最小生成樹算法(Minimum Spanning Tree, MST)以及帶有代碼注釋的實(shí)現(xiàn)示例(使用Python語言):
1. Prim算法:
? ?- 原理:從一個起始頂點(diǎn)開始,逐步擴(kuò)展生成最小生成樹。每次選擇與當(dāng)前生成樹連接的邊中權(quán)重最小的邊,將其連接的頂點(diǎn)加入生成樹,直到生成樹包含所有頂點(diǎn)為止。
? ?- 實(shí)現(xiàn)(使用鄰接矩陣表示圖):
? ? ?```python
? ? ?def prim_mst(graph):
? ? ? ? ?num_vertices = len(graph)
? ? ? ? ?# 初始化最小生成樹的頂點(diǎn)集合和邊集合
? ? ? ? ?mst = []
? ? ? ? ?visited = [False] * num_vertices
? ? ? ? ?# 選擇初始頂點(diǎn)
? ? ? ? ?start_vertex = 0
? ? ? ? ?visited[start_vertex] = True
? ? ? ? ?while len(mst) < num_vertices - 1:
? ? ? ? ? ? ?min_weight = float('inf')
? ? ? ? ? ? ?min_edge = None
? ? ? ? ? ? ?# 遍歷已訪問頂點(diǎn)集合,尋找權(quán)重最小的邊
? ? ? ? ? ? ?for i in range(num_vertices):
? ? ? ? ? ? ? ? ?if visited[i]:
? ? ? ? ? ? ? ? ? ? ?for j in range(num_vertices):
? ? ? ? ? ? ? ? ? ? ? ? ?if not visited[j] and graph[i][j] < min_weight:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?min_weight = graph[i][j]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?min_edge = (i, j)
? ? ? ? ? ? ?if min_edge:
? ? ? ? ? ? ? ? ?# 將權(quán)重最小的邊加入最小生成樹
? ? ? ? ? ? ? ? ?mst.append(min_edge)
? ? ? ? ? ? ? ? ?visited[min_edge[1]] = True
? ? ? ? ?return mst
? ? ?```
2. Kruskal算法:
? ?- 原理:按照邊的權(quán)重從小到大選擇,并且不形成環(huán)路。將邊逐個加入生成樹,直到生成樹包含所有頂點(diǎn)為止。
? ?- 實(shí)現(xiàn)(使用并查集表示集合):
? ? ?```python
? ? ?class UnionFind:
? ? ? ? ?def __init__(self, num_vertices):
? ? ? ? ? ? ?self.parent = list(range(num_vertices))
? ? ? ? ? ? ?self.rank = [0] * num_vertices
? ? ? ? ?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):
? ? ? ? ? ? ?root_x = self.find(x)
? ? ? ? ? ? ?root_y = self.find(y)
? ? ? ? ? ? ?if self.rank[root_x] < self.rank[root_y]:
? ? ? ? ? ? ? ? ?self.parent[root_x] = root_y
? ? ? ? ? ? ?elif self.rank[root_x] > self.rank[root_y]:
? ? ? ? ? ? ? ? ?self.parent[root_y] = root_x
? ? ? ? ? ? ?else:
? ? ? ? ? ? ? ? ?self.parent[root_y] = root_x
? ? ? ? ? ? ? ? ?self.rank[root_x] += 1
? ? ?def kruskal_mst(graph):
? ? ? ? ?num_vertices = len(graph)
? ? ? ? ?# 初始化最小生成樹的邊集合
? ? ? ? ?mst = []
? ? ? ? ?# 按權(quán)重升序排序所有邊
? ? ? ? ?edges = []
? ? ? ? ?for i in range(num_vertices):
? ? ? ? ? ? ?for j in range(i+1, num_vertices):
? ? ? ? ? ? ? ? ?if graph[i][j] != 0:
? ? ? ? ? ? ? ? ? ? ?edges.append((i, j, graph[i][j]))
? ? ? ? ?edges.sort(key=lambda x: x[2])
? ? ? ? ?uf = UnionFind(num_vertices)
? ? ? ? ?for edge in edges:
? ? ? ? ? ? ?u, v, weight = edge
? ? ? ? ? ? ?if uf.find(u) != uf.find(v):
? ? ? ? ? ? ? ? ?# 加入當(dāng)前邊不會形成環(huán)路,將其加入最小生成樹
? ? ? ? ? ? ? ? ?mst.append((u, v, weight))
? ? ? ? ? ? ? ? ?uf.union(u, v)
? ? ? ? ?return mst
? ? ?```
3. Boruvka算法:
? ?- 原理:從每個連通分量中選擇最小權(quán)重的邊,將連通分量合并,重復(fù)這個過程,直到只剩下一個連通分量為止。
? ?- 實(shí)現(xiàn)(使用鄰接表表示圖):
? ? ?```python
? ? ?class Graph:
? ? ? ? ?def __init__(self, num_vertices):
? ? ? ? ? ? ?self.num_vertices = num_vertices
? ? ? ? ? ? ?self.edges = []
? ? ? ? ?def add_edge(self, src, dest, weight):
? ? ? ? ? ? ?self.edges.append((src, dest, weight))
? ? ?class Subset:
? ? ? ? ?def __init__(self, parent, rank):
? ? ? ? ? ? ?self.parent = parent
? ? ? ? ? ? ?self.rank = rank
? ? ?def find(subsets, i):
? ? ? ? ?if subsets[i].parent != i:
? ? ? ? ? ? ?subsets[i].parent = find(subsets, subsets[i].parent)
? ? ? ? ?return subsets[i].parent
? ? ?def union(subsets, x, y):
? ? ? ? ?if subsets[x].rank < subsets[y].rank:
? ? ? ? ? ? ?subsets[x].parent = y
? ? ? ? ?elif subsets[x].rank > subsets[y].rank:
? ? ? ? ? ? ?subsets[y].parent = x
? ? ? ? ?else:
? ? ? ? ? ? ?subsets[y].parent = x
? ? ? ? ? ? ?subsets[x].rank += 1
? ? ?def boruvka_mst(graph):
? ? ? ? ?num_vertices = graph.num_vertices
? ? ? ? ?mst = []
? ? ? ? ?subsets = [Subset(i, 0) for i in range(num_vertices)]
? ? ? ? ?cheapest = [-1] * num_vertices
? ? ? ? ?num_trees = num_vertices
? ? ? ? ?while num_trees > 1:
? ? ? ? ? ? ?for i in range(len(graph.edges)):
? ? ? ? ? ? ? ? ?src, dest, weight = graph.edges[i]
? ? ? ? ? ? ? ? ?x = find(subsets, src)
? ? ? ? ? ? ? ? ?y = find(subsets, dest)
? ? ? ? ? ? ? ? ?if x != y:
? ? ? ? ? ? ? ? ? ? ?if cheapest[x] == -1 or weight < graph.edges[cheapest[x]][2]:
? ? ? ? ? ? ? ? ? ? ? ? ?cheapest[x] = i
? ? ? ? ? ? ? ? ? ? ?if cheapest[y] == -1 or weight < graph.edges[cheapest[y]][2]:
? ? ? ? ? ? ? ? ? ? ? ? ?cheapest[y] = i
? ? ? ? ? ? ?for i in range(num_vertices):
? ? ? ? ? ? ? ? ?if cheapest[i] != -1:
? ? ? ? ? ? ? ? ? ? ?src, dest, weight = graph.edges[cheapest[i]]
? ? ? ? ? ? ? ? ? ? ?x = find(subsets, src)
? ? ? ? ? ? ? ? ? ? ?y = find(subsets, dest)
? ? ? ? ? ? ? ? ? ? ?if x != y:
? ? ? ? ? ? ? ? ? ? ? ? ?mst.append((src, dest, weight))
? ? ? ? ? ? ? ? ? ? ? ? ?union(subsets, x, y)
? ? ? ? ? ? ? ? ? ? ? ? ?num_trees -= 1
? ? ? ? ? ? ?cheapest = [-1] * num_vertices
? ? ? ? ?return mst
? ? ?```
這些是常見的最小生成樹算法及其代碼實(shí)現(xiàn)。每種算法都有不同的時間復(fù)雜度和適用場景,根據(jù)具體問題的需求選擇合適的算法。