1.普里姆算法
// Prim算法生成最小生成树void MiniSpanTree_Prim(MGraph G){int min, i, j, k;int adjvex[MAXVEX]; // 保存相关顶点下标int lowcost[MAXVEX]; // 保存相关顶点间边的权值lowcost[0] = 0; // V0作为最小生成树的根开始遍历,权值为0adjvex[0] = 0; // V0第一个加入// 初始化操作for( i=1; i < G.numVertexes; i++ ){lowcost[i] = G.arc[0][i]; // 将邻接矩阵第0行所有权值先加入数组adjvex[i] = 0; // 初始化全部先为V0的下标}// 真正构造最小生成树的过程for( i=1; i < G.numVertexes; i++ ){min = INFINITY; // 初始化最小权值为65535等不可能数值j = 1;k = 0;// 遍历全部顶点while( j < G.numVertexes ){// 找出lowcost数组已存储的最小权值if( lowcost[j]!=0 && lowcost[j] < min ){min = lowcost[j];k = j; // 将发现的最小权值的下标存入k,以待使用。}j++;}// 打印当前顶点边中权值最小的边printf("(%d,%d)", adjvex[k], k);lowcost[k] = 0; // 将当前顶点的权值设置为0,表示此顶点已经完成任务,进行下一个顶点的遍历// 邻接矩阵k行逐个遍历全部顶点for( j=1; j < G.numVertexes; j++ ){if( lowcost[j]!=0 && G.arc[k][j] < lowcost[j] ){lowcost[j] = G.arc[k][j];adjvex[j] = k;}}}}
2.克鲁斯卡尔算法
int Find(int *parent, int f){while( parent[f] > 0 ){f = parent[f];}return f;}// Kruskal算法生成最小生成树void MiniSpanTree_Kruskal(MGraph G){int i, n, m;Edge edges[MAGEDGE]; // 定义边集数组int parent[MAXVEX]; // 定义parent数组用来判断边与边是否形成环路for( i=0; i < G.numVertexes; i++ ){parent[i] = 0;}for( i=0; i < G.numEdges; i++ ){n = Find(parent, edges[i].begin); // 4 2 0 1 5 3 8 6 6 6 7m = Find(parent, edges[i].end); // 7 8 1 5 8 7 6 6 6 7 7if( n != m ) // 如果n==m,则形成环路,不满足!{parent[n] = m; // 将此边的结尾顶点放入下标为起点的parent数组中,表示此顶点已经在生成树集合中printf("(%d, %d) %d ", edges[i].begin, edges[i].end, edges[i].weight);}}}
无论是普里姆算法(Prim)还是克鲁斯卡尔算法(Kruskal),他们考虑问题的出发点都是:为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能的小。
普里姆算法是以某顶点为起点,逐步找各个顶点上最小权值的边来构建最小生成树的。
克鲁斯卡尔算法是我们从边出发,因为权值是在边上嘛,直接去找最小权值的边来构建生成树是自然的想法,这也是克鲁斯卡尔算法的精髓。
