计算机算法设计与分析 最小生成树 实验报告.docx
《计算机算法设计与分析 最小生成树 实验报告.docx》由会员分享,可在线阅读,更多相关《计算机算法设计与分析 最小生成树 实验报告.docx(8页珍藏版)》请在冰豆网上搜索。
计算机算法设计与分析最小生成树实验报告
×××学院实验报告纸
计算机科学与工程学院(院、系)网络工程专业071班组计算机算法设计与分析课
学号200710224133姓名121实验日期2010.教师评定
最小生成树问题
1、实验目的:
通过简单的实际应用例子,了解和掌握最小生成树问题的要点和方法。
2、算法分析:
设计思想:
图的存储使用数组表示法,即邻接矩阵存储,结构体包含图的邻接矩阵,当前顶点数和弧数。
图的初始化使用二重循环得到顶点和表的权值,邻接矩阵的打印使用二重for循环。
然后把图各边的权值按从小到大排序;然后依次把最小边加入进来,即生成最小生成树。
克鲁斯卡尔算法:
假设WN=(V,{E})是一个含有n个顶点的连通网,按照构造最小生成树的过程为:
先构造一个只含n个顶点,而边集为空的子图,之后,从网的边集E中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。
依次类推,直至只有一棵树,也即子图中含有n-1条边为止。
1、设定图的抽象数据类型:
ADTGraph{
数据对象V:
V是具有相同特性的数据元素的集合,称为点集.
数据关系R:
R={VR}
VR={(v,w)|v,w属于V,(v,w)表示v和w之间存在的路径}
基本操作P:
CreatGraph(&G,V,VR)
初始条件:
V是图的顶点集,VR是图中弧的集合.
操作结果:
按V和VR是定义构造图G.
Sort(edge*,MGraph*)
初始条件:
图G存在,各边权值已知;
操作结果:
对权值进行排序;
Find(int*,int)
初始条件:
前者为已存在的集合,后者为集合中的元素;
操作结果:
查找函数,确定后者所属子集;
MiniSpanTree(MGraph*)
初始条件:
图G存在,各边权值已知;
操作结果:
生成最小树;
Swapn(edge*,int,int)
初始条件:
图G存在,各边权值已知;
操作结果:
交换某两个边的权值;
2图的存储结构
typedefstruct
{
intadj;
intweight;
}AdjMatrix[MAX][MAX];
typedefstruct
{
AdjMatrixarc;
intvexnum,arcnum;
}MGraph;
typedefstruct
{
intbegin;
intend;
intweight;
}edge;
3本程序包含的模块
}
1)初始化操作,结构体定义;
2)函数声明模块;
3)函数定义模块;
4)主程序模块
Main()
{
调用函数生成图;
判断图是否为空;(空则从新输入)
调用函数生成最小生成树;
退出;
3、程序代码:
#include
#include
#defineM20
#defineMAX20
typedefstruct
{
intbegin;
intend;
intweight;
}edge;
typedefstruct
{
intadj;
intweight;
}AdjMatrix[MAX][MAX];
typedefstruct
{
AdjMatrixarc;
intvexnum,arcnum;
}MGraph;
voidCreatGraph(MGraph*);
voidsort(edge*,MGraph*);
voidMiniSpanTree(MGraph*);
intFind(int*,int);
voidSwapn(edge*,int,int);
voidCreatGraph(MGraph*G)
{
inti,j,n,m;
printf("请输入边数和顶点数:
");
scanf("%d%d",&G->arcnum,&G->vexnum);
for(i=1;i<=G->vexnum;i++)
{
for(j=1;j<=G->vexnum;j++)
{
G->arc[i][j].adj=G->arc[j][i].adj=0;
}
}
for(i=1;i<=G->arcnum;i++)
{
printf("\n请输入有边的2个顶点");
scanf("%d%d",&n,&m);
while(n<0||n>G->vexnum||m<0||n>G->vexnum)
{
printf("输入的数字不符合要求请重新输入:
");
scanf("%d%d",&n,&m);
}
G->arc[n][m].adj=G->arc[m][n].adj=1;
getchar();
printf("\n请输入%d与%d之间的权值:
",n,m);
scanf("%d",&G->arc[n][m].weight);
}
printf("邻接矩阵为:
\n");
for(i=1;i<=G->vexnum;i++)
{
for(j=1;j<=G->vexnum;j++)
{
printf("%d",G->arc[i][j].adj);
}
printf("\n");
}
}
voidsort(edgeedges[],MGraph*G)
{
inti,j;
for(i=1;iarcnum;i++)
{
for(j=i+1;j<=G->arcnum;j++)
{
if(edges[i].weight>edges[j].weight)
{
Swapn(edges,i,j);
}
}
}
printf("权排序之后的为:
\n");
for(i=1;iarcnum;i++)
{
printf("<<%d,%d>>%d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
voidSwapn(edge*edges,inti,intj)
{
inttemp;
temp=edges[i].begin;
edges[i].begin=edges[j].begin;
edges[j].begin=temp;
temp=edges[i].end;
edges[i].end=edges[j].end;
edges[j].end=temp;
temp=edges[i].weight;
edges[i].weight=edges[j].weight;
edges[j].weight=temp;
}
voidMiniSpanTree(MGraph*G)
{
inti,j,n,m;
intk=1;
intparent[M];
edgeedges[M];
for(i=1;ivexnum;i++)
{
for(j=i+1;j<=G->vexnum;j++)
{
if(G->arc[i][j].adj==1)
{
edges[k].begin=i;
edges[k].end=j;
edges[k].weight=G->arc[i][j].weight;
k++;
}
}
}
sort(edges,G);
for(i=1;i<=G->arcnum;i++)
{
parent[i]=0;
}
printf("最小生成树为:
\n");
for(i=1;i<=G->arcnum;i++)
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if(n!
=m)
{
parent[n]=m;
printf("<<%d,%d>>%d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
intFind(int*parent,intf)
{
while(parent[f]>0)
{
f=parent[f];
}
returnf;
}
intmain(void)
{
MGraph*G;
G=(MGraph*)malloc(sizeof(MGraph));
if(G==NULL)
{
printf("memoryallcationfailed,goodbye");
exit
(1);
}
CreatGraph(G);
MiniSpanTree(G);
system("pause");
return0;
}
4、时间复杂度分析:
由于在图的初始化以及邻接矩阵的打印时均使用了循环的嵌套,故其时间复杂度为O(n2)的;其他操作的时间复杂度均为O
(1)。
5、总结:
通过一个简单的实际例子,比较好地掌握了最小生成树的算法思想。