详细的说明代码中已经差不多了,不再赘述:
用到的图如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct e{
int otherVertex;//保存另一条边的标号
int edgeWeight;//保存另一条边的权重
} Edge;
void prim(int *edge,int vertexNum);
int main(){
puts("***************普利姆算法(求连通图分最小生成树)****************");
puts("***************************************************************");
puts("最小生成树:包括n各顶点,但是只有n-1个边的一棵树,想要使权值相加为最小.");
//这里把图写死了,只是为了实现这个算法
int edge[6][6]={0};
int i ,j;
edge[0][1] = 6;
edge[0][2] = 1;
edge[0][3] = 5;
edge[1][2] = 5;
edge[2][3] = 5;
edge[2][5] = 4;
edge[1][4] = 3;
edge[2][4] = 6;
edge[3][5] = 2;
edge[4][5] = 6;
edge[1][0] = 6;
edge[2][0] = 1;
edge[3][0] = 5;
edge[2][1] = 5;
edge[3][2] = 5;
edge[5][2] = 4;
edge[4][1] = 3;
edge[4][2] = 6;
edge[5][3] = 2;
edge[5][4] = 6;
prim(edge,6);
return 0;
}
void prim(int *edge,int vertexNum){
Edge *closeEdge;
int i;
closeEdge = (Edge *)malloc(sizeof(Edge)*vertexNum); //候选集合中的点到生成树中的点的一组最小边
//顶点集合的下标代表一个顶点的标号 如果而值1代表改点存在该集合中0代表该点不存在该集合
int *U = (int *)malloc(sizeof(int)*vertexNum);//生成树顶点集合
int *S_U = (int *)malloc(sizeof(int)*vertexNum);//候选集合顶点 它和U集合的顶点是互补的
//初始化U集合和S_U集合
U[0]= 1;//将0标号这个点放入集合中
S_U[0] = 0;//将0标号的点移除S_U集合
for(i = 1;i<vertexNum;i++){
U[i]=0;
S_U[i]=1;
}
//初始化closeEdge 如果一个顶点已经在生成树集合中 就不需要在closeEdge中出现了
closeEdge[0].otherVertex = 0;
closeEdge[0].edgeWeight = 0;
for(i=1;i<vertexNum;i++){
int weight = *(edge+vertexNum*0+i);
if(weight!=0){
closeEdge[i].otherVertex = 0;
closeEdge[i].edgeWeight = weight;
}
}
int j =0;
//开始普里姆算法 找出n-1条边,一次循环一条边
for(i = 1;i<vertexNum;i++){
//从closeEdge中找出权值最小的边
int minVertexIndex = minWeight(closeEdge,vertexNum,S_U);
//将该顶点加入U中,并从S_U中移除
U[minVertexIndex] = 1;
S_U[minVertexIndex] =0;
printf("(%d,%d);",closeEdge[minVertexIndex].otherVertex+1,minVertexIndex+1);
//更新closeEdge 也就是新加入到S集合(生成树集合)中的顶点到S_U集合(候选集合)中的顶点是否存在权值更小的边,如果有,那么更新它
for(j=0;j<vertexNum;j++){
//如果该点在候选集合中存在 并且该点是顶点S集合中顶点minVertexIndex的邻接边
if(S_U[j]&&*(edge+vertexNum*minVertexIndex+j)!=0){
if(*(edge+vertexNum*minVertexIndex+j)<closeEdge[j].edgeWeight){
closeEdge[j].otherVertex = minVertexIndex;
closeEdge[j].edgeWeight = *(edge+vertexNum*minVertexIndex+j);
}
}
}
}
i = 0;
puts("\n输出closeEdge:");
for(i;i<vertexNum;i++){
printf("(%d,%d),权重:%d;",closeEdge[i].otherVertex+1,i+1,closeEdge[i].edgeWeight);
}
}
//返回最小权值边的顶点中在S_U中的顶点的下标
int minWeight(Edge *closeEdge,int vertexNum,int *S_U){
int i = 1,minVertexIndex = vertexNum,minWeight = 9999999; //权值只能小于9999999 不然会出错
for(i = 0;i<vertexNum;i++){
if(S_U[i]&&closeEdge[i].edgeWeight <minWeight){//如果该点存在在S_U中 并且权重小于minWeight
minWeight = closeEdge[i].edgeWeight;
minVertexIndex = i;
}
}
return minVertexIndex;
}
输出结果如下:
***************普利姆算法(求连通图分最小生成树)****************
***************************************************************
最小生成树:包括n各顶点,但是只有n-1个边的一棵树,想要使权值相加为最小.
(1,3);(3,6);(6,4);(3,2);(2,5);
输出closeEdge:
(1,1),权重:0;(3,2),权重:5;(1,3),权重:1;(6,4),权重:2;(2,5),权重:3;(3,6),权重:4;