普利姆算法基础

普利姆算法

应用场景–修路问题

普利姆算法基础_第1张图片

最小生成树

修路问题的本质就是最小生成树问题,先介绍一下最小生成树(Minimum Cost Spanning Tree),简称MST

  1. 给定一个带权的无相连通图,如何选择一颗生成树,使树上所有边上权的总和最小,这就叫最小生成树
  2. N个顶点,一定有N-1条边
  3. 包含全部顶点
  4. N-1条边都在图中
  5. 求最小生成树的算法主要是普利姆算法克鲁斯卡尔算法

普利姆算法基础_第2张图片

算法介绍

  1. 普利姆算法求最小生成树,也就是在包含n个顶点的连通图中,找出只有(n-1)条边包含所有n个顶点的联通子图,也就是所谓的极小连通子图

  2. 普利姆算法如下:

    普利姆算法基础_第3张图片

  3. 修路问题图解:

普利姆算法基础_第4张图片

代码

package L十大算法.Prime;


import java.util.Arrays;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/1/15 0015  15:43
 * 普利姆算法
 */
public class PrimeAlgrothim {

    public static void main(String[] args) {

        //测试看看图是否创建成功
        char[]  data = new char[]{'A','B','C','D','E','F','G'};
        int verxs = data.length;

        //邻接矩阵的关系使用二维数组表示,10000这个大数,表示两个点不联通
        int [][]weight=new int[][]{
                {10000,5,7,10000,10000,10000,2},
                {5,10000,10000,9,10000,10000,3},
                {7,10000,10000,10000,8,10000,10000},
                {10000,9,10000,10000,10000,4,10000},
                {10000,10000,8,10000,10000,5,4},
                {10000,10000,10000,4,5,10000,6},
                {2,3,10000,10000,4,6,10000},};

        //创建Graph对象
        MGraph mgraph = new MGraph(verxs);

        //创建一个MiniTree
        MinTree minTree = new MinTree();
        minTree.createGraph(mgraph,verxs,data,weight);

        //输出
        minTree.showGraph(mgraph);

        //测试普利姆水泥发
        minTree.prime(mgraph,0);
    }
}


//最小生成树---->村庄的图
class MinTree{

    /**
     *
     * @param graph   图对象
     * @param verxs   图对应的顶点个数
     * @param data   图的各个顶点的值
     * @param weight  图的临街矩阵
     */
    //创建图的领结矩阵
    public  void createGraph(MGraph graph,int verxs,char[] data,int[][] weight){
        int i,j;
        for(i=0;i<verxs;i++){  //顶点
            graph.data[i] = data[i];
            for(j=0;j<verxs;j++){
                graph.weight[i][j] = weight[i][j];
            }
        }
    }
        //显示图的临街矩阵
        public void showGraph(MGraph graph){
            for(int i=0;i<graph.verxs;i++){
                for(int[] link : graph.weight){
                    System.out.println(Arrays.toString(link));
                }
            }
         }



         //编写prime算法,得到最小生成树
        /*
         * @param graph  图
         * @param v  表示从图的第几个顶点开始生成'A'->0
         */
        public void prime(MGraph graph,int v){

            //visited[]  标记节点(顶点)是否访问过
            int[] visited = new int[graph.verxs];

            //visited[] 默认元素值都是0,表示没有访问过
            for(int i=0;i<graph.verxs;i++){
                visited[i]=0;
            }

            //把当前节点标记为已经访问
            visited[v]=1;

            //h1和h2记录这两个顶点下标
            int h1 = -1;
            int h2 = -1;
            //将minWeight初始化为最大值,后面再遍历过程中,会被替换
            int minWeight = 10000;
            for(int k=1;k<graph.verxs;k++){ //因为有graph.verxs顶点,普利斯木算法结束后,有graph.versx-1边

                //这个是确定每一次生成的子图和哪个节点的距离最近
                for(int i=0;i<graph.verxs;i++){//遍历已经访问的节点;i节点表示被访问过的结案
                    for(int j=0;j<graph.verxs;j++){ //遍历没有访问的节点;j表示还没有被访问
                        if(visited[i]==1&&visited[j]==0&&graph.weight[i][j]<minWeight){
                            //替换minWeight(寻找已经访问过的节点和未访问过的节点间的权值最小的边)
                            minWeight = graph.weight[i][j];
                            h1 = i;
                            h2 = j;
                        }
                    }
                }
                //找到一条边最小
                System.out.println("边<"+graph.data[h1]+","+graph.data[h2]+">权值"+minWeight);
                //将当前节点标记为已经访问
                visited[h2]=1;
                //minWeight重新设置为最大值10000
                minWeight=10000;
            }

        }
}



class MGraph{

    int verxs; //表示图的节点的个数

    char[] data;//存放节点数据

    int[][] weight; //存放边,就是我们的邻近矩阵

    public MGraph(int verxs) {
        this.verxs = verxs;
        data = new char[verxs];
        weight = new int[verxs][verxs];
    }
}

你可能感兴趣的:(Java数据结构与算法整理)