程序员必会十大算法之Prim算法

Posted 独饮敌敌畏丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序员必会十大算法之Prim算法相关的知识,希望对你有一定的参考价值。

问题


①胜利乡有7个村庄(A, B,C,D,E,F,G),现在需要修路把7个村庄连通
②各个村庄的距离用边线表示(权),比如A-B距离5公里
③问:如何修路保证各个村庄都能连通,并且总的修建公路总里程最短?

代码

重点理解createMinTree中的三层for循环

public class Main {
    public static void main(String[] args) {
        char[] data = {'A','B','C','D','E','F','G'};
        int[][] weight = {
                {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,10006,10000,5,4},
                {10000,10000,10000,4,5,10000,6},
                {2,3,10000,10000,4,6,10000}};

        MGraph mGraph = new MGraph(data.length);
        mGraph.createGraph(data,weight);
        mGraph.showGraph();

        createMinTree(mGraph,0);
    }

    /**
     *
     * @param mGraph 表示图
     * @param startIndex 表示开始的点的下标 比如从A开始,则传0
     */
    public static void createMinTree(MGraph mGraph,int startIndex){
        if (mGraph.vertexNum == 0){
            return;
        }
        //创建是否访问数组
        boolean[] isVisited = new boolean[mGraph.vertexNum];
        //全部初始化为 未访问
        for (int i = 0;i < mGraph.vertexNum;i++){
            isVisited[i] = false;
        }
        //将开始的点 设置成 已访问
        isVisited[startIndex] = true;

        //创建遍历到的两个点的下标
        int v1 = -1;
        int v2 = -1;
        //创建两点间距离,默认不可达
        int v1Tov2 = 10000;

        //总共 遍历mGraph.vertexNum - 1 次,因为是一条边一条边遍历的,生成最小生成树的时候,边的数目==点的数目-1
        for (int k = 0;k < mGraph.vertexNum - 1;k++){

            //每一次都要遍历 已访问的节点集合 和 未访问的节点集合
            //但是这个集合我们没创建出来,所以只能通过遍历所有的点,通过isVisited进行筛选
            for (int i = 0;i < mGraph.vertexNum;i++){
                for (int j = 0;j < mGraph.vertexNum;j++){
                    //如果有一个点已经访问,另外一个点没有被访问,且两点间可达或者距离比当前记录的举例还要小
                    if (isVisited[i] && !isVisited[j] && mGraph.weight[i][j] < v1Tov2){
                        //将v1Tov2更新
                        v1Tov2 = mGraph.weight[i][j];

                        v1 = i;
                        v2 = j;
                    }
                }
            }

            //遍历一次,得到两个点,即一个边,把这个边记录下来
            System.out.println("边<"+ mGraph.data[v1] + "," + mGraph.data[v2]+"> 权值:"+ v1Tov2);

            //然后为下一次遍历做初始化操作
            isVisited[v2] = true;
            v1Tov2 = 10000;
        }
    }
}
//这是图
class MGraph{
    //节点数目
    int vertexNum;
    //节点
    char[] data;
    //边的权值
    int[][] weight;

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

    //图的创建
    public void createGraph(char[] mData,int[][] mWeight){
        if (vertexNum == 0){
            return;//节点数目为0 无法创建
        }

        for (int i = 0;i < data.length;i++){
            data[i] = mData[i];
        }

        for (int i = 0;i < mWeight.length;i++){
            for (int j = 0;j < mWeight.length;j++){
                weight[i][j] = mWeight[i][j];
            }
        }
    }

    //打印图
    public void showGraph(){
        if (vertexNum == 0){
            return;
        }

        for (int[] oneLine: weight){
            for (int oneNum: oneLine){
                System.out.print(oneNum + " ");
            }
            System.out.println();
        }
    }
}

结果

<A,G> 权值:2<G,B> 权值:3<G,E> 权值:4<E,F> 权值:5<F,D> 权值:4<A,C> 权值:7

以上是关于程序员必会十大算法之Prim算法的主要内容,如果未能解决你的问题,请参考以下文章

程序员必会十大算法之弗洛伊德算法

程序员必会十大算法之Kruskal算法

程序员必会十大算法之骑士周游问题

十大排序算法(程序员必会)

LeetCode代码模板,刷题必会

程序员必会算法之冒泡排序