普利姆算法
数据结构:
1.pick数组,代表是否被选中
2.mindis数组,下标就是点的编号,数值为当前已选点的集合中的所有点到这个点的距离的最小值
3.father数组,下标也是点的编号,如果该点没有选定,则为-1,否则为更新mindis时对应路径和其相连的点的编号
步骤:
1.接入一个顶点
2.遍历和这个顶点相连的所有边,拿出相连的顶点,(如果该顶点没有被选中)到mindis里面进行比较
如果小于,则更新相应的mindis和father,并且和当前最小值min进行比较,如果还是小于,那么记录当前点的编号,更新min
3.遍历完这个顶点之后,拿出记录的最小路径编号,把这个编号的pick改为1说明选中
4.按照上述路径再对这个顶点进行处理即可。
由于我们需要遍历和一个点相连的所有边,所以用链式前向星
对于链式前向星的遍历细节,请到我的[数据结构No1]中查看详情
prim算法需要先判断是否是连通图再做决定
而且创建图时,应该设置为无向边,也就是起点终点呼唤设置两条边
如果起点终点相同那么可以直接跳过
如果重边其实也不需要管,因为prim算法会把和结点所有相连的最小边找出来
细节问题:
一般从node=1开始进行遍历,但是别忘了pick[1]=1;也就是先把第一个点标记再进行下面的步骤
void prim()
{
cnt=0;
int tmp;
pick[node]=1;
while(1)
{
min=inf;
//遍历和node相连的结点和他们之间的距离
for(int i=head[node];i;i=edge[i].nextEdge)//i是边的下标,head[node]即和node相连的第一条边的下标
{
tmp=edge[i].endNode;//和node相连的结点
if(pick[tmp]==0)//该节点还没有被选中
{
if(mindis[tmp]>edge[i].dis)//比较当前已存在边和当前结点的距离
{
//如果当前的tmp更小,那么更新mindis和father里面的值
mindis[tmp]=edge[i].dis;
father[tmp]=node;
}
}
}
//开始找到已经储存的点里面最短的边
for(int i=1;i<=n;i++)
{
if(pick[i]==0&&mindis[i]!=inf)//从还没有pick的点并且可以到达的边里面挑选
{
if(mindis[i]<min)//如果当前结点边小于min值,更新min值,并记录结点编号
{
min=mindis[i];
minnode=i;
}
}
}
//找到所需结点之后,直接选定,并且更新下次要寻找的node为当前的node
pick[minnode]=1;
node=minnode;
cnt++;
if(cnt==n)
{
break;
}
sum=sum+min;
}
}