if(nVex[i])
{
Vexs[i].vex=i;//结点i存在
Vexs[i].gno=i;//不同的结点赋予不同的连通分量编号
nVexs++;
}
}
(*Graph).VexList=Vexs;
(*Graph).EdgeList=Edges;
(*Graph).nvex=nVexs;
(*Graph).nedge=nEdges;
printf("从文件读取到图如下:
\n");
Output_Graph(Graph);
fclose(fp);
return0;
}
//*************************************************************
//****输出图的结构
//*************************************************************
voidOutput_Graph(TpGraphGraph)
{
inti,j;
printf("顶点--信息\n");
for(i=1;invex;i++)
printf("%4d--%-4d\n",i,Graph->VexList[i].vex);
printf("\n边-尾-头-权\n");
for(j=0;jnedge;j++)
printf("%2d-%-2d-%2d-%-2d\n",j+1,Graph->EdgeList[j].vtail,Graph->EdgeList[j].vhead,Graph->EdgeList[j].wght);
}
//*************************************************************
//****根据图采用Kruskal算法建立并输出最小生成树
//*************************************************************
intKruskal_Tree(TpGraphGraph)
{
inti,j,k,s;
intmin=10000;
intEdges=1;
TpEdgemin_wght_edge;//权值最小的边
printf("\n最小生成树结构如下:
\n");
while(Edgesnvex-1)
{
min=10000;
for(i=0;inedge;i++)
{
if((min>Graph->EdgeList[i].wght)&&(Graph->EdgeList[i].flag==0))
{
min=Graph->EdgeList[i].wght;//记录当前的最小权值
min_wght_edge=&Graph->EdgeList[i];//选择的最小边
}
}
if(Graph->VexList[min_wght_edge->vtail].gno==Graph->VexList[min_wght_edge->vhead].gno)//最小边上两个顶点的连通分量相同
{
min_wght_edge->flag=-1;//舍去这条边
for(j=0;jnedge;j++)//舍去无向图中对应的另一条边
if(Graph->EdgeList[j].vtail==min_wght_edge->vhead&&Graph->EdgeList[j].vhead==min_wght_edge->vtail)
{
Graph->EdgeList[j].flag=-1;
break;
}
}
else
{
min_wght_edge->flag=1;//将这条边加入MST
for(k=0;knedge;k++)//加入无向图中对应的另一条边
if((Graph->EdgeList[k].vtail==min_wght_edge->vhead)&&(Graph->EdgeList[k].vhead==min_wght_edge->vtail))
{
Graph->EdgeList[k].flag=1;
break;
}
Ass_Con_Comp(Graph,min_wght_edge->vtail,min_wght_edge->vhead);//统一连通分量
printf("第%d条边:
<%d,%d>,权值为%d\n",Edges,min_wght_edge->vtail,min_wght_edge->vhead,min_wght_edge->wght);
++Edges;
}
}
return0;
}
//*************************************************************
//****统一一个集合内所有顶点的连通分量
//*************************************************************
voidAss_Con_Comp(TpGraphGraph,intVex1,intVex2)
{
inti;
for(i=0;inedge;i++)
{
if((Graph->EdgeList[i].flag==1)&&(Graph->EdgeList[i].vtail==Vex1)&&(Graph->EdgeList[i].vhead!
=Vex2))
if(Graph->VexList[Graph->EdgeList[i].vhead].gno!
=Graph->VexList[Vex1].gno)
Ass_Con_Comp(Graph,Graph->EdgeList[i].vhead,Vex1);
if((Graph->EdgeList[i].flag==1)&&(Graph->EdgeList[i].vhead==Vex1)&&(Graph->EdgeList[i].vtail!
=Vex2))
if(Graph->VexList[Graph->EdgeList[i].vtail].gno!
=Graph->VexList[Vex1].gno)
Ass_Con_Comp(Graph,Graph->EdgeList[i].vtail,Vex1);
}
Graph->VexList[Vex2].gno=Graph->VexList[Vex1].gno;
for(i=0;inedge;i++)
{
if((Graph->EdgeList[i].flag==1)&&(Graph->EdgeList[i].vtail==Vex2)&&(Graph->EdgeList[i].vhead!
=Vex1))
if(Graph->VexList[Graph->EdgeList[i].vhead].gno!
=Graph->VexList[Vex2].gno)
Ass_Con_Comp(Graph,Vex2,Graph->EdgeList[i].vhead);
if((Graph->EdgeList[i].flag==1)&&(Graph->EdgeList[i].vhead==Vex2)&&(Graph->EdgeList[i].vtail!
=Vex1))
if(Graph->VexList[Graph->EdgeList[i].vtail].gno!
=Graph->VexList[Vex2].gno)
Ass_Con_Comp(Graph,Vex2,Graph->EdgeList[i].vtail);
}
Graph->VexList[Vex2].gno=Graph->VexList[Vex1].gno;
}
九、程序运行结果:
运行结果
十、实验结论:
通过实现最小生成树的算法,我理解了图的数据结构存储表示:
使用结构体存储,结构成员存储图的边信息和点信息,让我对Kruskal算法有了而深刻的理解并能在实际应用中熟练地运用它。
最后,这次实验加强了我对算法的理解,提高了我的编程能力。
十一、总结及心得体会:
1、图有多种存储方式,如邻接矩阵存储,邻接链表存储,还有结构体存储;个人认为结构体存储更方便具体;
2、输入地址时容易很容易出错,应建立错误输入的解决方案;
3、EOF:
读取文件时文件结束的标志;
4、在无向图中需要同时删除两条边;
5、统一连通分量时采用递归方法最简单;
6、最小生成树的边条数为结点数减一;
7、一般情况下不需要考虑键盘缓冲,但某些情况如果没有考虑到他则会影响对输入的判断;
8、在文件开始时声明函数的结构使得在调用函数时不用考虑函数定义的先后顺序。