Prim 算法是一种用于寻找权重最小的生成树的算法。它会从某个节点开始,逐步添加与该节点直接相连且权值最小的节点,直到所有节点都被添加到生成树中。
我们可以使用优先队列实现 Prim 算法:
public List<Edge> primMST(List<Edge>[] graph) {
int n = graph.length;
boolean[] visited = new boolean[n];
PriorityQueue<Edge> pq = new PriorityQueue<>((a, b) -> a.weight - b.weight);
pq.offer(new Edge(0, 1, graph[0].get(1).weight)); // 起始边 (0, 1) 入队列
List<Edge> res = new ArrayList<>();
visited[0] = true; // 标记节点 0 为已访问
while (!pq.isEmpty()) {
Edge e = pq.poll(); // 取出权重最小的边
if (visited[e.to]) continue; // 如果e的终点节点已被访问则跳过
res.add(e); // 添加当前边到结果
visited[e.to] = true; // 标记e的终点节点为已访问
for (Edge edge : graph[e.to]) { // 遍历e的终点节点相邻的所有边
if (!visited[edge.to]) pq.offer(edge); // 如果边的终点未被访问则入队列
}
}
return res;
}
算法流程:
- 访问节点 0,将节点 0 相邻的所有边入队列。标记节点 0 为已访问。
- 从队列中弹出权重最小的边 e。如果 e 的终点节点已被访问则跳过。
- 将 e 添加到结果,并标记 e 的终点节点为已访问。
- 将 e 的终点节点相邻的所有未访问边入队列。
- 重复步骤 2-4,直到队列为空。得到的所有边构成最小生成树。
- 返回结果,得到最小生成树的所有边。
时间复杂度 O(nlogn),空间复杂度 O(n)。
所以,Prim 算法的关键是:
- 使用优先队列找出权重最小的边。
- 如果某条边的终点节点已访问,则跳过这条边。
- 添加选中的边到结果,并标记相关节点为已访问。
- 将选中的边的终点相邻的未访问边入队列。
- 重复此过程直到队列为空,得到最小生成树的所有边。