一、目的
本实验旨在理解和掌握Prim算法的基本原理,并通过编程实现该算法,以求解给定无向加权图的最小生成树。通过本实验,能够加深对最小生成树概念的理解,并提升编程能力。
二、原理
Prim算法是一种求解最小生成树的贪心算法。其基本原理是:从任意一个顶点开始,每次选择连接已选择的顶点集合与未选择的顶点集合之间的最短边,并将该边的另一个顶点加入已选择的顶点集合,直到所有顶点都被选择为止。最终,所选的边构成的就是最小生成树。
三、步骤
-
实现Prim算法:
- 在
PrimMST
类中实现Prim算法,包括:
- 在
- 私有成员变量,包括顶点数量
V
、邻接矩阵graph
、最短距离数组key
、MST标记数组mstSet
和父顶点数组parent
。 - 构造函数,用于初始化图的顶点数量和相关数组。
prim
方法,实现Prim算法的核心逻辑。updateKey
方法,用于更新key
数组和优先队列。
-
编写主函数:
- 在
main
方法中:
- 在
- 创建
Scanner
对象以读取用户输入。 - 读取顶点数量
V
和邻接矩阵。 - 选择源顶点的索引。
- 调用
prim
方法并传入源顶点索引。 - 打印每个顶点到源顶点的最短距离。
- 打印MST的边。
四、代码展示
package com.lwtstu5.practice;
import java.util.Scanner;
import java.util.PriorityQueue;
public class PrimMST {
private int V; // 顶点的数量
private int[][] graph; // 图的邻接矩阵表示
private int[] key; // 存储每个顶点到MST的最短距离
private boolean[] mstSet; // 标记顶点是否已经在MST中
private int[] parent; // 存储MST中每个顶点的父顶点
public PrimMST(int V) {
this.V = V;
this.graph = new int[V][V];
this.key = new int[V];
this.mstSet = new boolean[V];
this.parent = new int[V];
}
// 构造函数、辅助函数等...
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number of vertices");
int V = scanner.nextInt();
PrimMST pmst = new PrimMST(V);
System.out.println("Enter the adjacency matrix:");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
pmst.graph[i][j] = scanner.nextInt();
}
}
int src = 0; // 选择源顶点
pmst.prim(src);
System.out.println("Vertex \t Distance from Source");
for (int i = 0; i < V; i++)
System.out.println(i + " \t " + pmst.key[i]);
// 输出MST的边
System.out.println("Edges of the MST:");
for (int i = 1; i < V; i++) {
System.out.println(pmst.parent[i] + " - " + i + " (weight: " + pmst.graph[pmst.parent[i]][i] + ")");
}
scanner.close();
}
public void prim(int src) {
for (int i = 0; i < V; i++) {
key[i] = Integer.MAX_VALUE;
mstSet[i] = false;
}
key[src] = 0;
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); // 边的权重作为优先级
pq.offer(new int[]{src, 0}); // 顶点索引和权重
while (!pq.isEmpty()) {
int[] currEdge = pq.poll();
int u = currEdge[0];
if (!mstSet[u]) {
mstSet[u] = true;
updateKey(u, currEdge[1], pq);
}
}
}
private void updateKey(int src, int weight, PriorityQueue<int[]> pq) {
for (int v = 0; v < V; v++) {
if (graph[src][v] != 0 && !mstSet[v] && graph[src][v] < key[v]) {
key[v] = graph[src][v];
parent[v] = src;
pq.offer(new int[]{v, graph[src][v]});
}
}
}
}
五、测试结果
这个输出表示:
- 顶点
0
到源顶点(它自己)的距离是0
。 - 顶点
1
到源顶点的距离是1
,这是通过边(0, 1)
的权重。 - 顶点
2
到源顶点的距离是3
,这是通过边(1, 2)
的权重。 - 顶点
3
到源顶点的距离是4
,这是通过边(2, 3)
的权重。
MST的边是:
- 顶点
0
到顶点1
的边,权重为1
。 - 顶点
1
到顶点2
的边,权重为3
。 - 顶点
2
到顶点3
的边,权重为5
。