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

来源:互联网 发布:淘宝网围巾专卖 编辑:程序博客网 时间:2024/05/01 04:40

Prim算法是求最小生成树的一种常见算法,简单谈一下笔者自己的理解。

算法思路

  1. 设已经确定的点集为P,初始为空。设还未确定的点集为Q,初始为该图所有点的集合。设已经确定的边为X,初始为空。
  2. 选取任意一点作为起始点,将该点添加到集合P中,并从Q中移除该点。
  3. 从P中找到一个点A,从Q中找到一个点B,使得2点之间的路径AB的权值最小。
  4. 将路径AB添加到X,将Q中的点B添加到集合P中,并从Q中移除该点。
  5. 重复3~4,直至所有点确定路径。

代码思路

  1. 采用邻接矩阵保存图。
  2. 创建一个临时数组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。
  3. 创建临时数组mst,长度为总点数,用于保存步骤2的最短距离m对应的边关系。即每次添加一个点到P后,会更新P与剩余各点之间的最短距离m,此时会记录最短距离的边AB的起始点和结束点。
    例如lowcost[3]=m,mst[3]=2表示下标为3的点A到P的距离为m,该连线是A与P中下标为2的点B的连线。
  4. 初始化:选取图的点集合的下标为0的点A,作为初始点。将图的边矩阵中,A与各点的距离(权重)写入lostcost数组作为初始值,并将mst各元素置零。创建临时变量n=1,表示已经确定的点数,用作循环结束的判断。
  5. 遍历lowcost数组,找出最小的值(排除0和65535),即当前集合P中任意一点到Q中任意一点的最短距离(权重)。记录下标minid。
  6. 将lowcost[minid]置为零,表示该点已经添加到P。
  7. 更新新添加到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为一个新的值。
  8. 循环执行5~7,直至所有点的路径确定,即当n>=总点数跳出循环。

代码实现(Java版)

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[n];        int[] mst = new int[n];        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);    }}
1 0
原创粉丝点击