Prim算法解析及Java代码实现(附图)

Prim算法

普里姆(Prim)算法,是用来求加权连通图的最小生成树的算法。

基本思想 :

        对于图G而言,V是所有顶点的集合;现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最小生成树中的边。 从所有uЄU,vЄ(V-U) (V-U表示出去U的所有顶点)的边中选取权值最小的边(u, v),将顶点v加入集合U中,将边(u, v)加入集合T中,如此不断重复,直到U=V为止,最小生成树构造完毕,这时集合T中包含了最小生成树中的所有边。

伪代码:

图解:

以上图G4为例,来对普里姆进行演示(从第一个顶点A开始通过普里姆算法生成最小生成树)。

初始状态:V是所有顶点的集合,即V={A,B,C,D,E,F,G};U和T都是空! 
第1步:将顶点A加入到U中。 
此时,U={A}。 
第2步:将顶点B加入到U中。 
上一步操作之后,U={A}, V-U={B,C,D,E,F,G};因此,边(A,B)的权值最小。将顶点B添加到U中;此时,U={A,B}。 
第3步:将顶点F加入到U中。 
上一步操作之后,U={A,B}, V-U={C,D,E,F,G};因此,边(B,F)的权值最小。将顶点F添加到U中;此时,U={A,B,F}。 
第4步:将顶点E加入到U中。 
上一步操作之后,U={A,B,F}, V-U={C,D,E,G};因此,边(F,E)的权值最小。将顶点E添加到U中;此时,U={A,B,F,E}。 
第5步:将顶点D加入到U中。 
上一步操作之后,U={A,B,F,E}, V-U={C,D,G};因此,边(E,D)的权值最小。将顶点D添加到U中;此时,U={A,B,F,E,D}。 
第6步:将顶点C加入到U中。 
上一步操作之后,U={A,B,F,E,D}, V-U={C,G};因此,边(D,C)的权值最小。将顶点C添加到U中;此时,U={A,B,F,E,D,C}。 
第7步:将顶点G加入到U中。 
上一步操作之后,U={A,B,F,E,D,C}, V-U={G};因此,边(F,G)的权值最小。将顶点G添加到U中;此时,U=V。

此时,最小生成树构造完成!它包括的顶点依次是:A B F E D C G

 


public class Prim {
	/** 邻接矩阵, 为二维数组 */
    int[][] matrix;
    /** 设置最大权重范围, 表示正无穷 */
    int MAX_WEIGHT = Integer.MAX_VALUE;
    /** 顶点个数 */
    int size;
 
    /**
     * 普里姆算法:先初始化拿到第一个顶点相关联的权值元素放到数组中-> 找到其中权值最小的顶点下标-》再根据该下标,将该下标顶点相关联的权值加入到数组中-》循环遍历处理
     */
    public void prim() {
        /** 存放当前到全部顶点最小权值的数组,如果已经遍历过的顶点权值为0,无法到达的为正无穷 */
        int[] tempWeight = new int[size];   
        int minWeight;   /** 当前到下一个最小权值顶点的最小权值 */
        int minId;       /** 当前到下一个最小权值的顶点 */
        int sum = 0;     /** 权值总和 */
        
        //初始化"顶点的权值数组", 第一个顶点时, 到其他顶点的权值即为邻接矩阵的第一行
        for (int i = 0; i < size; i++) {
        	//将与v0顶点有边的权值存入数组
            tempWeight[i] = matrix[0][i];
        }
 
        System.out.println("从顶点v0开始查找");
        //最外层循环开始
        for (int i = 1; i < size; i++) {
            //每次循环找出当前到下一个最小权值的顶点极其最小权值 
            minWeight = MAX_WEIGHT;
            minId = 0;
            
            for (int j = 1; j < size; j++) {
                //如果权值不为0 且权值小于 minWeight
                if (tempWeight[j] > 0 && tempWeight[j] < minWeight) {
                	//让当前权值为最小值
                    minWeight = tempWeight[j];
                    //将当前最小值的下标存入minId 
                    minId = j;
                }
            }
            
            //找到目标顶点minId,他的权值为minWeight。
            System.out.println("找到顶点:v" + minId + " 权值为:" + minWeight);
            sum += minWeight;   //加上对应边的权重,更新sum值
            
            
            /**
             * 算法核心所在:将目标顶点到各个顶点的权值与当前tempWeight数组中的权值做比较,
             *             如果前者比后者到某个顶点的权值更小,
             *             将前者到这个顶点的权值更新入后者。
             */
            
            //将"第minId个顶点的权值"标记为0,意味着这顶点已经排序过了(或者说已经加入了最小树结果中)
            tempWeight[minId] = 0;
            for (int j = 1; j < size; j++) {
            	//若下标为minId 的顶点各边权值 小于 此前这些顶点未被加入生成树权值
                if (tempWeight[j] != 0 && matrix[minId][j] < tempWeight[j]) {
                	//将较小权值存入tempWeight
                    tempWeight[j] = matrix[minId][j];
                }
            }
        }
        //最外层循环结束
        
        System.out.println("最小权值总和为:" + sum);
    }
 
    private void createGraph(int index) {  //index表示顶点个数
        size = index;
        matrix = new int[index][index];    //邻接矩阵是一个长宽相等的正方形矩阵
        //邻接矩阵中每一行的数组, 按照原图以此填充
        int[] v0 = { 0, 10, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
        int[] v1 = { 10, 0, 18, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, MAX_WEIGHT, 12 };
        int[] v2 = { MAX_WEIGHT, 18, 0, 22, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 8 };
        int[] v3 = { MAX_WEIGHT, MAX_WEIGHT, 22, 0, 20, MAX_WEIGHT, MAX_WEIGHT, 16, 21 };
        int[] v4 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 20, 0, 26, MAX_WEIGHT, 7, MAX_WEIGHT };
        int[] v5 = { 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 26, 0, 17, MAX_WEIGHT, MAX_WEIGHT };
        int[] v6 = { MAX_WEIGHT, 16, MAX_WEIGHT, 24, MAX_WEIGHT, 17, 0, 19, MAX_WEIGHT };
        int[] v7 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, 7, MAX_WEIGHT, 19, 0, MAX_WEIGHT };
        int[] v8 = { MAX_WEIGHT, 12, 8, 21, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0 };
        matrix[0] = v0;
        matrix[1] = v1;
        matrix[2] = v2;
        matrix[3] = v3;
        matrix[4] = v4;
        matrix[5] = v5;
        matrix[6] = v6;
        matrix[7] = v7;
        matrix[8] = v8;
    }
 
    public static void main(String[] args) {
        Prim graph = new Prim();
        graph.createGraph(9);
        graph.prim();
    }
 
}

结果:

代码中所用的图示:

最小生成树:99

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值