最小生成树Prim和Kruskal的java实现

最小生成树概述

最小生成树是从无向带权图中找出 n-1条边,以最小的代价将图上的n个顶点连接起来,有两种最小生成树算法,一种是Prim算法,选结点;另一种是Kruskal, 选边
Prim算法构造最小生成树过程
在这里插入图片描述
Kruskal算法构造最小生成树过程
在这里插入图片描述

Java实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Edge{
    int start;
    int end;
    int weight;
    public Edge(){}
    public Edge(int start,int end,int weight){
        this.start = start;
        this.end = end;
        this.weight = weight;
    }
}

class UnionFind{
    int[] root;
    public UnionFind(int n){
        root = new int[n];
        for(int i=0;i<n;i++){
            root[i] = i;
        }
    }
    public void uion(int x,int y){
        root[find(x)] = find(y);
    }
    public int find(int x){
        if(x != root[x]){
            root[x] = find(root[x]);
        }
        return root[x];
    }
}

class MST{
    //Prim 算法
    public ArrayList<Integer> prim(int[][] graph, int cur){
        int n = graph.length;

        int cost = 0;
        ArrayList<Integer> res = new ArrayList<>();

        boolean[] visited = new boolean[n];
        int[] dist = new int[n];

        res.add(cur);
        //第一个访问的结点
        visited[cur] = true;
        for(int i=0;i<n;i++){
            dist[i] = graph[cur][i];
        }
        for(int i=1;i<n;i++){               //剩余n-1个顶点
            int mindist = Integer.MAX_VALUE;
            int index=0;

            for(int j=0;j<n;j++){           //从当前顶点出发,找一个最近的未被访问过的顶点
                if(!visited[j] && dist[j]<mindist){
                    mindist = dist[j];
                    index = j;
                }
            }
            res.add(index);
            cost += mindist;
            visited[index] = true;
            //将以index为起点的点算进来,加入到当前集合,使新加入的顶点与当前集合的距离不为INF
            for(int k=0;k<n;k++){
                if(!visited[k] && graph[index][k]<dist[k]){
                    dist[k] = graph[index][k];
                }
            }
        }
        System.out.println("min cost tree:"+cost);
        return res;
    }

    //Kruskal 算法
    public ArrayList<Integer> kruskall(ArrayList<Edge> edges,int n_vertex){
        //对边进行排序?
        //每次找最小的边,并将边两端的顶点union到一个连通图
        //当边的数量等于顶点数量-1结束
        //对边的权重进行升序排序
        Collections.sort(edges, new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.weight-o2.weight;
            }
        });

        UnionFind unionFind = new UnionFind(n_vertex);
        //选取边,并对边上的顶点进行union
        int cost = 0,edge_cnt = 0;
//        ArrayList<Integer> res = new ArrayList<>();
        for(Edge edge:edges){
            if(unionFind.find(edge.start) != unionFind.find(edge.end)){
                unionFind.uion(edge.start,edge.end);
                cost += edge.weight;
                edge_cnt++;
                if(edge_cnt == n_vertex-1){
                    break;
                }
            }
        }
        System.out.println("min cost tree:"+cost);
        return null;
    }
}

public class PrimAlg {
    private static int INF = Integer.MAX_VALUE;
    public static void main(String[] args) {
        int n = 0;          //number of vertex
        int[][] graph = {
                {INF, 6, 1, 5, INF, INF},
                {6, INF, 5, INF, 3, INF},
                {1, 5,  INF, 5,  6,  4},
                {5, INF, 5,  INF, INF,2},
                {INF,3,  6,  INF, INF,6},
                {INF,INF,4,  2,   6, INF}
        };

        MST obj = new MST();
        //Prim
        ArrayList<Integer> res = obj.prim(graph,n);
        for(Integer a:res){
            System.out.print(a+"->");
        }

        //Kruskal
        //构建边集合
        int n_vertex = graph.length;
        ArrayList<Edge> edges = new ArrayList<>();
        for(int i=0;i<n_vertex;i++){
            for(int j=0;j<n_vertex;j++){
                if(graph[i][j] != Integer.MAX_VALUE){
                    edges.add(new Edge(i,j,graph[i][j]));
                }
            }
        }
        System.out.println("\nnumber of edges:"+edges.size());
        obj.kruskall(edges,n_vertex);
    }
}

参考:
https://blog.csdn.net/gettogetto/article/details/53216951
百度百科

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值