KrusKal求最小生成树

来源:互联网 发布:手机绘制平面图软件 编辑:程序博客网 时间:2024/04/28 04:27

这个算法的主要难点是:怎么避免连通图成环,可以用并查集算法

参考: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;}


1 0