算法思想:
把n个顶点看成n棵分离的树(每棵树只有一个顶点),每次选取可连接两个分离树中权值最小的边,把两个分离的树合并成一个新的树取代原来的两个分离树,重复n-1步后得到最小生成树.
1.myedge结构体数组存放所有的边及其权值,mytree结构体数组中存放生成的最小生成树的边,vex数组中存放该节点的父节点,初始值为都为0,代表每个节点的父节点都是本身.
2遍历图将边存放在myedge结构体数组中,然后根据权值从小到大排序.
3.选择权值最小的边所对应的权值在数组中的下标分别为p1,p2,然后分别求下标p1,p2所对应节点是否在一棵树上,如果不在,就将p1,p2所对应的节点连接在一起,将其加入mytree中,并更新p1所对应节点的父节点为p2所对应的节点,如果p1,p2在一颗树上,则找下一个组权值继续上述操作,直到myedge数组遍历完毕,mytree中就是我们要求的最小生成树.
下面是我实现的代码,图的建立代码之类的我就不贴出来了,和上一篇的一样,主要说一下KrusKal算法吧,先看代码把
typedef struct{
char start;
char end;
int weight;
}Edge[MAXVEX],EdgeNode;
void sort(Edge myedge,int num) //对每条边根据权值进行排序
{
int i,j;
EdgeNode p;
for(i=1;i<=num;i++){
for(j=i+1;j<num;j++){
if(myedge[i].weight > myedge[j].weight){
p=myedge[i];
myedge[i]=myedge[j];
myedge[j]=p;
}
}
}
}
int getPosition(AdjList *G,char c) //获得该节点在图顶点集合中的位置(数组下标)
{
int i;
for(i=1;i<=G->vexnum;i++){
if(G->vertex[i].vexdata == c){
return i;
}
}
}
int getEnd(int vex[],int i) //查看下标为i的节点当前的父节点;
{
while(vex[i]!=0){
i=vex[i];
}
return i;
}
void Kruskal(AdjList *G)
{
int i,p1,p2,index=1;
int k=1;
ArcNode *p;
int vex[MAXVEX];
Edge myedge,mintree;
for(i=1;i<=G->vexnum;i++)
{
visited[i]=0;
vex[i]=0;
}
for(i=1;i<=G->vexnum;i++){
visited[i]=1; //因为是无向图,邻接表中既存了AB,也会存BA,所以当A点遍历后,以A为尾的节点都将重复,不会加在myedge数组中;
p=G->vertex[i].head->next;
for(p;p!=NULL;p=p->next){
//printf("%d ",p->weight);
if(visited[p->adjvex]!=1){
myedge[k].start=G->vertex[i].vexdata;
myedge[k].end=G->vertex[p->adjvex].vexdata;
myedge[k].weight=p->weight;
k++;
}
}
}
sort(myedge,G->arcnum);
for(i=1;i<=G->vexnum;i++)
{
p1=getPosition(G,myedge[i].start);
p2=getPosition(G,myedge[i].end);
int m1=getEnd(vex,p1);
int m2=getEnd(vex,p2);
if(m1!=m2){ //当m1!=m2时,说明m1和m2没有在一颗树上,可以作为最小生成树的一条边。
vex[m1]=m2;
mintree[index++]=myedge[i];
}
}
for(i=1;i<index;i++){
printf("%c %c %d\n",mintree[i].start,mintree[i].end,mintree[i].weight);
}
}
比如说有一个图的信息为
5 7 A B C D E AB 10 AE 9 AD 11 EC 21 CD 2 BC 3 BD 7
则生成的邻接表为:
A: 2 10->4 11->5 9->NULL
B: 1 10->3 3->4 7->NULL
C: 2 3->4 2->5 21->NULL
D: 1 11->2 7->3 2->NULL
E: 1 9->3 21->NULL
边排序后得到:
C D 2
B C 3
B D 7
A E 9
A B 10
1.首先我们选择CD边,分别求得其对应的下标p1=3,p2=4;然后去求CD两颗树的父节点,由于其父节点是自身,我们返回的是m1=3,m2=4,m1不等于m2,说明两个节点不在同棵树上,可以作为最小生成树的一条边,加入数组mytree中,然后把C和D连在一起,更新vex [3]=4;代表C的父亲此时是D,D的父亲是自身;
2.我们选择BC,得到p1=2,p2=3,其父节点分别是m1=2,m2=4;加入mytree,连接BC,并让vex[2]=4;
3.选择BD,得到的父节点都是m1=m2=4,都是D,所以忽略本条边,继续下一次循环 ,一直到遍历完所有的边.
4.最后输出mytree中的数据,就是我们要求的最小生成树 .