最小生成树(Prim算法)

算法简介:

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克发现;并在1957年由美国计算机科学家罗伯特·普里姆独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

算法讲解:

该算法为求出图的最小生成树,首先我们需要两个数组来完成这个任务。一个数组用来保存当前节点的状态,另一个数组则用来保存到达该节点的最短距离。假设我们要求的这个图保存在一个二位数组里,保存节点状态的数组命名为vset,保存最短距离的数组命名为lowcast。

执行过程:

  1. 首先进行两个数组的初始化工作,将数组状态vset全部赋值为0(0代表当前节点未被并入最小生成树中,1代表当前节点已经被并入到最小生成树中)。将lowcast赋值为起始节点到其余各个节点的距离。
  2. 将起始节点的值置为1(vset[v0]=1),紧接着进行n-1(共有n个节点)次循环查找,知道求出最小生成树为止。这一步的每一次循环过程如下:
    1)求出lowcast的最小值,并把最小值指向的节点并入到生成树中。
    2)利用刚刚并入生成树的节点更新lowcast状态,得到一个最新的lowcast最短距离的数组。

代码实现:

void Prim(Griph g, int v0){
	//定义vset和lowcast两个数组
	int []vset = new vset[g.n];
	int []lowcast = new lowcast[g.n];
	int k,v;
	//初始化lowcast数组,并将vset全部置为0
	for(int i=0; i<g.n; i++){
		lowcast[i] = g.edge[v0][i];
		vset[i] = 0;
	}
	//首先访问v0
	vset[v0] = 1;
	//求最小生成树核心过程
	for(int i=0; i<g.n-1; i++){
		//暂时将最小值定为一个大数字
		int min = 65535;
		for(int j=0; j<g.n; j++){
			if(vset[j]==0 && lowcast[j] < min){
				min = lowcast[j];
				k = j;
			}
		}
		vset[k] = 1;
		v = k;
		//根据新节点的线索,更新lowcast
		for(int j=0 ;j<g.n; j++){
			if(vset[j] == 0 && g.edge[v][j] < lowcast[j]){
				lowcast[j] = g.edge[v][j];
			}
		}
	}
}

时间复杂度:

我们可以看到普里姆算法的核心为一个双层循环,双层循环内有两个并列的单层循环。第一个循环一定会执行,但是第二个循环不一定会执行。第一个循环中min=lowcast[j]为一个元操作,其每次循环执行次数为n。外层循环共执行n-1次,由此可见普里姆算法的时间复杂度为O(n^2)。普里姆算法的复杂度与节点个数有关而与边数无关。由此可见,普里姆算法适用于边数较多的稠密图。

posted @ 2018-07-17 11:16  AllenTung  阅读(260)  评论(0)    收藏  举报