一,Prim算法
Prim算法的核心思想其实就是将当前已经在最小生成树里的点作为一部分,将不在最小生成树里的点作为另一部分,然后选取连接两部分的边中权值最小的一条,将那一条边中不在生成树中的点并入到
生成树部分中,于是生成树部分又多了一个点,而非生成树部分少了一个点,形成了新的两部分,我这样说可能比较抽象,这里放个gif图加以理解。
就这样一直到所有的点全都归入到生成树部分,一棵最小生成树就形成了。
用邻接矩阵的方法进行算法实现
void minispantree_prim(mgraph g) { int min,i,j,k; int lowcost[maxvex]; //保存相关顶点间边的权值 lowcost[0] = 0; //初始化第一个权值为0,即v0加入生成树 //lowcost的值为0,在这里就是此下标的顶点已经加入生成树 for(i = 1;i < g.numvertexes;i++) { //循环除下标为0外的全部顶点 lowcost[i] = g.arc[0][i]; //讲v0顶点与之有边的权值存入数组 } for(i = 1;i < g.numvertexes;i++) { min = infinity; //初始化最小权值为∞ //通常设置为不可能的大数字如65535 j = 1;k = 0; while(j < g.numvertexes) { //循环全部顶点 if(lowcost[j] != 0 && lowcost[j] < min) { //如果权值不为0,且权值小于min min = lowcost[i]; //则让当前权值成为最小值 k = j; //将当前最小值的下标存入k } j++; } lowcost[k] = 0; //将当前顶点的权值设置为0,表示此顶点已经完成任务 for(j = 1;j < g.numvertexes;j++) { if(lowcost[j] != 0 && g.arc[k][j] < lowcost[j]) { //若下标为k顶点各边权值小于此前这些顶点未被加入生成树权值 lowcost[j] = g.arc[k][j]; //将较小权值存入lowcost } } } }
二 ,Kruskal算法
Kruskal算法的核心思想则是用一个边集数组将图的所有边存起来并且从小到大排好序,然后从最小的边开始遍历,如果不会构成回环那么就将其选入最小生成树中,否则就不选入。
动图演示如下。
算法实现
typedef struct{ int begin; int end; int weight; }Edge; int find(int parent[],int f) { //查找连线顶点的尾部下标 while(parent[f] > 0) f = parent[f]; return f; } void Kruskal(MGraph G){ int i,n,m; Edge edges[maxedge]; //定义边集数组 int parent[maxvex]; //定义一数组用来判断边与边是否形成环路 //此处省略将邻接矩阵转化为边集数组edges并按权由小到大排序的代码 for(int i=0;i<g.numvertexes;i++) parent[i] = 0; //初始化数组值为0 for(int i=0;i<g.numedges;i++) { //循环每一条边 n = find(parent,edges[i].begin); m = find(parent,edges[i].end); if(n != m) { //加入n与m不等,说明此边没有与现有生成树形成环路 parent[n] = m; //将此边的结尾顶点放入下标为起点的parent中表示此顶点已经在生成树集合中 } } }