您的位置:首页 > 其它

浅谈最小生成树的算法思路(一)Prim算法

2016-02-16 17:04 288 查看
Prim算法是求最小生成树的一种常见算法,简单谈一下笔者自己的理解。

算法思路

设已经确定的点集为P,初始为空。设还未确定的点集为Q,初始为该图所有点的集合。设已经确定的边为X,初始为空。

选取任意一点作为起始点,将该点添加到集合P中,并从Q中移除该点。

从P中找到一个点A,从Q中找到一个点B,使得2点之间的路径AB的权值最小。

将路径AB添加到X,将Q中的点B添加到集合P中,并从Q中移除该点。

重复3~4,直至所有点确定路径。

代码思路

采用邻接矩阵保存图。

创建一个临时数组lowcost,长度为总点数,用于表示当前时刻集合P与各点的距离。

例如lowcost[3]=m,3表示下标为3的点,当m为0表示该点已经在集合P中,即已经确定;当m为65535,表示该点与集合P暂时没有直接路径可到达;其他值表示该点与P可以直接通过一条连线到达,并且当前最短距离为m。

需要说明的是,这个数组是会不断变化的,最初,当P中只有一个点A的时候,lowcost表示A到各点的距离,这个时候有些点与点A没有直达路径,此时这些点是为65535的;而程序结束时,该数组的元素的值将都为0,因为所有点已经都添加到P了,此时各点到P的距离都为0。

创建临时数组mst,长度为总点数,用于保存步骤2的最短距离m对应的边关系。即每次添加一个点到P后,会更新P与剩余各点之间的最短距离m,此时会记录最短距离的边AB的起始点和结束点。

例如lowcost[3]=m,mst[3]=2表示下标为3的点A到P的距离为m,该连线是A与P中下标为2的点B的连线。

初始化:选取图的点集合的下标为0的点A,作为初始点。将图的边矩阵中,A与各点的距离(权重)写入lostcost数组作为初始值,并将mst各元素置零。创建临时变量n=1,表示已经确定的点数,用作循环结束的判断。

遍历lowcost数组,找出最小的值(排除0和65535),即当前集合P中任意一点到Q中任意一点的最短距离(权重)。记录下标minid。

将lowcost[minid]置为零,表示该点已经添加到P。

更新新添加到P的点minid与Q中各点的距离。即遍历图的边矩阵中起始点为minid的各元素,如果有比lowcost中对应元素的距离小的元素,则更新lostcost,同时更新mst。

例如,此时P中有3个点{A,B,C},Q中有2个点{D,E},C为刚刚添加的点。由于我们刚刚将C添加到P,所以执行步骤7之前的lostcost数组中保存着{A,B}到{C,D,E}的最短距离,比如lostcost为[0,0,0,Sd,Se]。当C添加进去之后,有可能之前AB到DE都距离比较远或者没有直接路径,而C到DE的距离很近,这个时候就需要比较C到DE的距离Scd和Sce有没有比Sd,Se更小,如果有则更新lostcost中的Sd,Se为一个新的值。

循环执行5~7,直至所有点的路径确定,即当n>=总点数跳出循环。

代码实现(Java版)

[code]public class Prim {
    static int MAX = 65535;//表示两点之间没有直接路径

    public static void prim(int[][] graph, int n) {
        char[] c = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'E', 'F'};
        int[] lowcost = new int
;
        int[] mst = new int
;
        int i, j, min, minid, sum = 0;
        //初始化数组,即将点A添加到P中,计算与各点的距离
        for (i = 1; i < n; i++) {
            lowcost[i] = graph[0][i];
            mst[i] = 0;
        }
        //i为已经确定的点数,由于点A已经确定,故初始化为1
        for (i = 1; i < n; i++) {
            min = MAX;
            minid = 0;
            //找到P到Q的最短路径,将点添加到P
            for (j = 1; j < n; j++) {
                if (lowcost[j] < min && lowcost[j] != 0) {
                    min = lowcost[j];
                    minid = j;
                }
            }
            System.out.println(c[mst[minid]] + "到" + c[minid] + " 权值:" + min);

            sum += min;
            lowcost[minid] = 0;
            //如果新添加到P的点minid带来了与Q中剩余点的更短路径,更新lowcost、mst数组
            for (j = 1; j < n; j++) {
                if (graph[minid][j] < lowcost[j]) {
                    lowcost[j] = graph[minid][j];
                    mst[j] = minid;
                }
            }
        }
        System.out.println("sum:" + sum);
    }

    public static void main(String[] args) {
        int[][] map = new int[][]{
                {0, 10, MAX, MAX, MAX, 11, MAX, MAX, MAX},
                {10, 0, 18, MAX, MAX, MAX, 16, MAX, 12},
                {MAX, MAX, 0, 22, MAX, MAX, MAX, MAX, 8},
                {MAX, MAX, 22, 0, 20, MAX, MAX, 16, 21},
                {MAX, MAX, MAX, 20, 0, 26, MAX, 7, MAX},
                {11, MAX, MAX, MAX, 26, 0, 17, MAX, MAX},
                {MAX, 16, MAX, MAX, MAX, 17, 0, 19, MAX},
                {MAX, MAX, MAX, 16, 7, MAX, 19, 0, MAX},
                {MAX, 12, 8, 21, MAX, MAX, MAX, MAX, 0}
        };
        prim(map, map.length);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: