C语言图的最小生成树prim算法(超详细版)

最近刚刚学习了图的最小生成树算法,也看了很多作者写的文章,在加上自己的钻研终于明白了其中的奥妙。
最小生成树算法的原理,大神们已经给了很详细的解释,有的还用图像说明。但美中不足的是,对代码的解释较少,这些代码让初学者阅读起来比较费力,也不利于初学者将彻底理解原理并将其转化成代码。
于是我写了一个关于代码的解释,希望对初学者有所帮助。我力求精确不误人子弟。

代码完全可以运行。
先建立一个图,这个图主要是为了测试用的,如果只写prim算法的函数而没数据运行就不直观。
建立一个visited[]数组保存已经求得的最小生成树上的点集
建立一个prevex[]保存最小生成树某个结点的前驱结点,可以通过回溯求得边集
这个图中的节点使用字母表示的,但没关系,我们只用这些字母的下标参与运算即可,不用让字母直接参与运算。如果非要获取字母,就用下标去数组中找它的对应关系求得字母即可。
我写的下面的代码,最终要求的结果是“按顺序求得的每次选中的节点名称”和“最小生成树的代价”。
上面讲的是一些必要的铺垫。接下来就按照普利姆算法的步骤写代码。
每一条我都会写注释

#include
#include
#define MAX_VERTEX_NUM 4//图的结点个数,这个会生成一个n*n的矩阵
#define START 'a' //从哪个结点开始求最小生成树,由于结点用字母表示,就先a开始吧
#define FIN 0	//两点之间没有连线,在矩阵中的存储方式
#define INIMIN 0x7fffffff//最大值32位int所能表示的最大值
typedef struct /* 图的数据结构 */
{
    char vex[MAX_VERTEX_NUM];/*结点*/
    int edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*矩阵*/
    int vexnum; /*结点的数目*/
    int edgenum; /* 边的数目*/
}MGraph2;
void mintree_2(MGraph2 *G){
	int visited[MAX_VERTEX_NUM]={0};//已经求得的结点
	int prevex[MAX_VERTEX_NUM]={-1};//已经求得的结点的前驱结点
	for(int i=0;i<MAX_VERTEX_NUM;i++){//初始化已经查找过的结点集合
		if(G->vex[i]==START){//从a开始生成最小生成树
			visited[i]=1;//a已经被求得,相当于把a加入了点集
			break;
		}
	}
	int sum=0;//最小生成树的代价
	for(int m=1;m<MAX_VERTEX_NUM;m++){//求m结点连通图的最小生成树,
										//每次求得一个结点,故要求m-1次
		int minj=0; int min=INIMIN;
		int prenode=0;
		for(int i=0;i<MAX_VERTEX_NUM;i++){//从点集里获取结点,未存在点集的跳过
										 //存在的,作为边中的i继续查找j
			if(!visited[i]){//未访问过
				continue;
			}
			for(int j=0;j<MAX_VERTEX_NUM;j++){//进入循环,查找使边权值最小的j
				if(visited[j]||G->edges[i][j]==FIN){
					continue;//如果j在点集内,跳过。如果两点之间没有边,跳过
				}
				if(min>G->edges[i][j]){//搜索最小值权值的边
					min=G->edges[i][j];
					minj=j;
					prenode=i;
					sum+=G->edges[i][j];
				}
			}
		}
		printf("本次选择了结点:%c\n",G->vex[minj]);
		visited[minj]=1;//将最小权值的边标记为已求得
		prevex[minj]=prenode;//记录前驱结点
	}
	printf("最小生成树的总代价:%d",sum);
}

//以下是代码调用部分,可以运行。
void _mintree(){
MGraph2 *mgraph=(MGraph2*)malloc(sizeof(MGraph2));
	mgraph->vex[0]='a';
	mgraph->vex[1]='b';
	mgraph->vex[2]='c';
	mgraph->vex[3]='d';
	mgraph->edgenum=MAX_VERTEX_NUM;mgraph->vexnum=MAX_VERTEX_NUM;
	mgraph->edges;
	int **arr=(int**)malloc(sizeof(int*)*MAX_VERTEX_NUM);
	for(int i=0;i<MAX_VERTEX_NUM;i++){
		*arr=(int*)malloc(sizeof(int)*MAX_VERTEX_NUM);
	}
	for(int i=0;i<MAX_VERTEX_NUM;i++){
		for(int j=0;j<MAX_VERTEX_NUM;j++){
			mgraph->edges[i][j]=0;
		}
	}
	mgraph->edges[0][0]=0;
	mgraph->edges[0][1]=2;mgraph->edges[0][2]=1;mgraph->edges[0][3]=4;
	mgraph->edges[1][0]=2;mgraph->edges[1][2]=4;mgraph->edges[1][3]=1;
	mgraph->edges[2][0]=1;mgraph->edges[2][1]=4;mgraph->edges[2][3]=1;
	mgraph->edges[3][0]=4;mgraph->edges[3][1]=1;mgraph->edges[3][2]=1;
	for(int i=0;i<MAX_VERTEX_NUM;i++){
		for(int j=0;j<MAX_VERTEX_NUM;j++){
			printf("%d ",mgraph->edges[i][j]);
		}
		printf("\n");
	}
	mintree_2(mgraph);
}

运行结果如下所示
C语言图的最小生成树prim算法(超详细版)_第1张图片

你可能感兴趣的:(算法)