最小生成树算法中Prim是通用的一种算法。其大致的思想可以用通俗的语言去描述。首先看一段其他博客中的专业描述:
“设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边”。
Prim算法的思想就是遍历所有最小权值的边,当然这种遍历是在依次添加顶点的基础上。通俗来讲,以下图为例,可以首先选择V1为为起点,然后遍历V = {v2,v3,v4,v5,v6}这其余的5个顶点;遍历完成后发现V3到V1的值最小,那么将V3加入到已经遍历的节点集合,暂时用W表示,则W={v1,v3},V1开始时默认起始点,已经加入;此时V = {v2,v4,v5,v6},然后遍历这几个顶点到W中顶点的权值哪个最小,然后选择哪个,下一个应该选择V6;依次类推,这就是Prim基本的算法思想,算法复杂度当然为n*n;
以下是《大话数据结构》中的代码实现,同时加了自己的一些理解注释
/*图的邻接矩阵定义*/
typedef char VertexType;
typedef int EdgeType;
#devine MAXVEX 100
#define INFINITY 65535
typedef struct
{
VertexType vexs[MAXVEX];//顶点表
EdgeType arc[MAXVEX][MAXVEX];//边表。可以表示权值的大小
int numVertexes,numEdges;//边和顶点的最大个数
}MGraph;
void MiniSpanTree_Prim(MGraph G)
{
int min,i,j,k;
int adjvex[MAXVEX] ={0};//存放顶点的下标,可以看做一个存放已经被选中的顶点的集合
int lowcost[MAXVEX] ={0};//存放边的权值
/*先选择一个起始点,加入从0开始,我们的顶点采用自然数字0~MAXVEX*/
adjvex[0] = 0;
lowcost[0]=0;//初始化第一条边为0,代表节点0已经加入了adjvex的集合
for(j=0;j<G.numVertexes;j++)
{
lowcost[j]=arc[0][j];//将与第一个节点边的权值存入到数组
adjvex[j] = 0;//全都初始化为0的下标
}
/*开始遍历出去第一个节点的其他节点*/
for(i=1;i<G.numVertexes;i++)
{
min = INFINITY;
for(j=0;j<G.numVertexes;j++)
{
if(lowcost[j]!=0 && min>lowcost[j])
{
min = lowcost[j];
k=j;//记录下当前这个点的下标
}
j++;
}//循环退出时,便找到了离当前节点最近距离的点
printf("(%d,%d)"adjvex[k],k);
lowcost[k]=0;//代表第j个节点已经被遍历了。
/*下边这个循环是来寻找新加入的节点与其他顶点的最小值,然后存入lowcost数组中,同时更新下标数组*/
if(j=1;j>G.numVertexes;j++)
{
if(lowcost[j]!=0; && G.arc[k][j] < lowcost[j])
{
lowcost[j] = G.arc[k][j];//将较小值存入到lowcost中
adjvex[j] = k;//将k的下边存入顶点数组
}
}
}
}