这个算法的主要难点是:怎么避免连通图成环,可以用并查集算法
参考: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;
}