这个算法的主要难点是:怎么避免连通图成环,可以用并查集算法
参考:http://blog.csdn.net/dellaserss/article/details/7724401/
图例:
代码:
#include<stdio.h> #include<stdlib.h> /*主要采用并查集来判断是否成环,加入了路径压缩*/ #include <malloc.h> #include <string.h> #define MAX 20 #define nLENGTH(a) (sizeof(a)/sizeof(a[0])) #define eLENGTH(a) ( sizeof(a) / sizeof(char) )/ ( sizeof(a[0]) / sizeof(char) ) //邻接矩阵 typedef struct _graph { char vexs[MAX]; // 顶点集合 int vexnum; // 顶点数 int edgnum; // 边数 }Graph, *PGraph; // 边的结构体 typedef struct _EdgeData { char start; // 边的起点 char end; // 边的终点 int weight; // 边的权重 }EData; //指向节点的位置 int point_node(PGraph g,char c) { for(int i=0;i<g->vexnum;i++) { if(g->vexs[i]==c) { return i; } } return -1; } //对边按权值大小排序 void Sort_edg(EData edg[],int e) { int i,j; for (i=0; i<e; i++) { for (j=i+1; j<e; j++) { if (edg[i].weight > edg[j].weight) { // 交换"第i条边"和"第j条边" EData tmp = edg[i]; edg[i] = edg[j]; edg[j] = tmp; } } } for(j=0;j<e;j++) { printf("%c--%c\t%d",edg[j].start,edg[j].end,edg[j].weight); printf("\n"); } } /*并查集的主要思路以下:*/ //------------------------------------------------------------------------------- //找到根顶点 int FindRoot(int a[],int p) { int r=p; while(a[r]!=r) r=a[r]; //路径压缩 int x=p,j; while(x!=r) { j=a[x]; //j 保存 p 的父顶点 a[j]=r; //把 终端顶点 r 赋给 p的父顶点 x=j; //把j值赋给x,不断循环,把父级的父级 r 一次一次赋给 x ,直到x与 r相等 } return r; } //-------------------------------------------------------------------------------- void KrusKalTree(int b[][3],char a[],int L,int e) { int rand=0; PGraph g; //矩阵 EData edg[MAX];//保存边数组 int ch[MAX]={0,1,2,3,4,5,6};//并查集用 EData rets[MAX]; //用来存放选择好的边 g=(PGraph)malloc(sizeof(Graph)); //memset()第一个参数 是地址,第二个参数是开辟空间的初始值,第三个参数是开辟空间的大小 printf("顶点个数:\n");//顶点数 g->vexnum=L; printf("%d\n",g->vexnum); printf("边个数:\n");//边数 g->edgnum=e; printf("%d\n",g->edgnum); //初始化顶点 for(int j=0;j<g->vexnum;j++) { g->vexs[j]=a[j]; } //得到边的数组 for(int i=0;i<e;i++) { edg[i].start=char(b[i][0]); edg[i].end=char(b[i][1]); edg[i].weight=b[i][2]; } //对边进行排序 Sort_edg(edg,e); //进行并查集求解 for(int k=0; k< e ; k++) { int p1,p2,m,n; p1=point_node(g,edg[k].start); p2=point_node(g,edg[k].end); //找他们的根顶点 m=FindRoot(ch,p1); n=FindRoot(ch,p2); if(m!=n) { ch[m]=n; rets[rand++]=edg[k]; } } printf("得到的最小生成树:\n"); //打印已经得到的最小生成树的边 for(j=0;j<rand;j++) { printf("%c--%c\t%d",rets[j].start,rets[j].end,rets[j].weight); printf("\n"); } //通过循环,可以看出,压缩路径起了作用,不用通过循环即可,找到终端顶点 for(j=0;j<rand;j++) { printf("%d\t",ch[i]); } } //测试 int main() { int i,j; PGraph gp; //测试用例 char a[]={'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int b[][3]={ {'A', 'B',12}, {'A', 'F',16}, {'A', 'G',14}, {'B', 'F',7}, {'B', 'C',10}, {'C', 'F',6}, {'C', 'E',5}, {'C', 'D',3}, {'D', 'E',4}, {'E', 'F',2}, {'E', 'G',8}, {'F', 'G',9}}; //测试用例 int n=nLENGTH(a); int e=eLENGTH(b); KrusKalTree(b,a,n,e); return 0; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。