最小生成树的 Krusal 算法和 Prim 算法 Java 实现

Posted 一个拿着底层薪资操着架构师的心的码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树的 Krusal 算法和 Prim 算法 Java 实现相关的知识,希望对你有一定的参考价值。

Kruscal算法实现最小生成树

主方法

 1 import java.util.Arrays;
 2 import java.util.Comparator;
 3 import java.util.Scanner;
 4 
 5 public class Solution4 {
 6     static class Edge{
 7         int u, v;
 8         int cost;
 9     };
10     public static Edge[] edges = new Edge[10010];   // 存储所有的边的数据
11     public static int[] root = new int[110];      // 存储每个结点所在集合
12     public static int e, v;     // 分别表示边数和顶点数
13 
14     public static void main(String[] args) {
15         Scanner in = new Scanner(System.in);
16         while((e = in.nextInt()) != 0){
17             // 初始化每个顶点所在的集合为自己单独所处的集合
18             for(int i = 0; i < 110; i++){
19                 root[i] = i;
20             }
21             // 读入所有边的数据
22             v = in.nextInt();
23             int a, b;
24             for(int i = 0; i < e; i++){
25                 edges[i] = new Edge();
26                 edges[i].u = in.nextInt();
27                 edges[i].v = in.nextInt();
28                 edges[i].cost = in.nextInt();
29             }
30 
31             // 进行 Kruscal 算法构建最小生成树
32             int price = Krusal();
33             if(price == -1)
34                 System.out.println("?");
35             else
36                 System.out.println(price);
37         }
38 
39     }
40 }

Krusal()函数

 1 // Kruscal 算法生成最小生成树
 2 public static int Krusal(){
 3     // 对所有边进行排序
 4     Arrays.sort(edges, 0, e, new Comparator<Edge>(){
 5         public int compare(Edge e1, Edge e2){
 6             return e1.cost - e2.cost;
 7         }
 8     });
 9     int cost = 0;   // 总花费
10     int edgeCount = 0;  // 当前已归纳的边数
11     // 遍历所有的边,统计当前生成树中边的数量
12     for(int i = 0; i < e; i++){
13         // 判断 边的链各个顶点是否属于同一个集合
14         int uRoot = findRoot(edges[i].u);
15         int vRoot = findRoot(edges[i].v);
16         // 如果不输于则合并
17         if(uRoot != vRoot){
18             root[vRoot] = uRoot;
19             cost += edges[i].cost;
20             edgeCount++;
21             if(edgeCount == v - 1)
22                 return cost;
23         }
24         // 如果边的数量等于顶点数减一,那么可以退出循环
25     }
26     return -1;
27 
28 }

这里主要注意的并查集的findRoot()方法,非常巧妙,内部使用了一个递归来压缩路径

1   private static int findRoot(int u) {
2         if(root[u] == u)
3             return u;
4         int uRoot = findRoot(root[root[u]]);    // 路径压缩
5         root[u] = uRoot;
6         return uRoot;
7     }

 

prim()算法实现最小生生成树

 1 import java.util.Arrays;
 2 import java.util.Scanner;
 3 
 4 public class PrimTest {
 5     // 构建最小生成树
 6     public static int[][] G = new int[110][110];    // 村庄的图
 7     public static boolean[] vis = new boolean[110]; // 判断某个村庄是否已经被访问过
 8     public static int[] dis = new int[110];     // 存放每个村庄到当前生成树集合的距离
 9     public static int e;
10     public static final int INF = 1 << 30;
11     public static int v;
12 
13     public static void main(String[] args) {
14         // 读入数据
15         Scanner in = new Scanner(System.in);
16 
17         e = in.nextInt();
18         v = in.nextInt();
19         for (int i = 0; i < v; i++) {
20             Arrays.fill(G[i], INF);
21         }
22         Arrays.fill(vis, false);
23         int a, b;
24         // 对这个数据进行prim最小生成树算法
25         for (int i = 0; i < e; i++) {
26             a = in.nextInt();
27             b = in.nextInt();
28             G[a - 1][b - 1] = in.nextInt();
29             G[b - 1][a - 1] = G[a - 1][b - 1];
30         }
31 
32         // 如果仍有点的距离为 -1,说明不可达,输出?
33         int price = prim(0);
34         if (price == -1)
35             System.out.println("?");
36         else
37             System.out.println(price);
38     }
39 }

prim()函数

 1 private static int prim(int u) {
 2     int price = 0;
 3     // 初始化距离数组
 4     Arrays.fill(dis, INF);
 5     dis[u] = 0;
 6     // 对每个村庄进行循环判断,每次选出其中一个点
 7     for (int i = 0; i < v; i++) {
 8         int min = INF, vil = -1;
 9         for (int j = 0; j < v; j++) {
10             if (vis[j] == false && dis[j] < min) {
11                 min = dis[j];
12                 vil = j;
13             }
14         }
15         if (min == INF) {
16             return -1;      // 说明不可达
17         }
18         // 标记为已访问
19         vis[vil] = true;
20         price += dis[vil];
21         // 更新剩下的dis[]值,更新这个村庄周边到当前生成树的最短距离
22         for (int j = 0; j < v; j++) {
23             if (vis[j] == false && G[vil][j] != INF && dis[j] > G[vil][j]) {
24                 dis[j] = G[vil][j];
25             }
26         }
27     }
28     return price;
29 }

 

以上是关于最小生成树的 Krusal 算法和 Prim 算法 Java 实现的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树的prim算法 边的权值为啥不能为负值

最小生成树的prim算法 边的权值为啥不能为负值

最小生成树的Prim算法

Kruskal算法和Prim算法构造它的一棵最小代价生成树的过程

关于最小生成树的Prim算法和Kruskal算法

求krusal算法原理