图的最短路径算法与数据结构课程设计.docx
- 文档编号:4952646
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:15
- 大小:157.69KB
图的最短路径算法与数据结构课程设计.docx
《图的最短路径算法与数据结构课程设计.docx》由会员分享,可在线阅读,更多相关《图的最短路径算法与数据结构课程设计.docx(15页珍藏版)》请在冰豆网上搜索。
图的最短路径算法与数据结构课程设计
图的最短路径
一、问题描述
最小生成树是一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有个结点,并且有保持图连通的最小的边,最小生成树在实际问题中具有一定的应用价值,如在城市之间建设网络,要保证网络的连通性,求最经济的设计方法。
求解最小生成树时,可以采用普里母算法和克鲁斯卡尔算法。
二、基本要求
1、选择合适的储存结构,完成网的建立;
2、利用普里母算法求网的最少生成树,并输出结果;
3、利用克鲁斯卡尔求网的最少生成树,并输出结果;
4、采用邻接矩阵和邻接表两种储存结构;
三、测试数据
对右图进行测试
右图是6个顶点的10个边的连通图
六个顶点分别是
v1v2v3v4v5v6
边和边上的权植分别是
v1v26
v1v31
v1v45
v2v35
v2v53
v3v45
v3v56
v3v64
v4v62
v5v66
四、算法思想
克鲁斯卡尔算法思想是:
假设连通图N=(V,{E}),则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。
以此类推,直至T中所有顶点都在同一连通分量上为止。
普里母算法思想是:
假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。
算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:
在所有u∈U,v∈V—U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。
此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。
为实现这个算法需附设辅助数组closedge,以记录从U到V-U具有最小代价的边。
对每个顶点vi∈V-U,在辅助数组中存在一个相应分量closedge[i-1],它包括两个域,其中lowcost储存该边的权。
显然,closedge[i-1].lowcost=Min{cost(u,vi)|u∈U},vex∈U},vex域存储该边依附的在U中的顶点。
五、模块
克鲁斯卡尔算法和普里母算法都要用到以下的算法
intLocateVex(MgraphG,Vertexu),矩阵求点u所在位置;
voidCreateGraph(Mgraph/ALGraph&G),建立带权邻接矩阵/邻接表的结构;
voidkruskal2(ALGraphG),邻接链表的克鲁斯卡尔算法;
voidkruskal(MGraphG),邻接矩阵的克鲁斯卡尔算法;
intminimum(ALGraph/MGraphG,structarrywq[]),邻接表/邻接矩阵求最小的权值;
voidMiniSpanTree_PRIM1(ALGraphG,VertexTypeu),邻接表的普里姆算法;
voidMiniSpanTree_PRIM2(MGraphG,VertexTypeu),邻接矩阵的普里姆算法。
六、数据结构//(ADT)
1、邻接表的储存结构如下
邻接表的结点结构信息
typedefstructArcNode{/*定义边结点*/
intadjvex;/*该弧指向的顶点的位置*/
intweight;/*该弧的权重*/
structArcNode*nextarc;/*指向下一条弧的指针*/
}ArcNode;
邻接表的表头向量的结点结构信息
typedefstructVNode{
VertexTypedata;/*顶点信息*/
ArcNode*firstarc;/*指向第一条依附该顶点的弧的指针*/
}VNode,AdjList[MAX_VERTEX_NUM];//定义图结点
邻接表的表头带权图的结构信息
typedefstruct{
AdjListvertices;/*表头向量*/
intvexnum,arcnum;//顶点数和弧数
}ALGraph;//定义图
2、邻接矩阵的储存结构如下
typedefintAdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];/*邻接距阵*/
邻接矩阵带权图的结构信息
structMGraph
{Vertexvexs[MAX_VERTEX_NUM];/*顶点向量*/
AdjMatrixarcs;/*邻接矩阵*/
intvexnum,arcnum;/*顶点数和弧数*/
};
七、源程序
#include
#include
#include
#defineMAX_NAME5/*顶点值最大字符数*/
#defineMAX_VERTEX_NUM20/*最大顶点数*/
typedefcharVertex[MAX_NAME];/*(邻接矩阵用)顶点名字串*/
typedefcharVertexType[MAX_NAME];/*(邻接链表用)顶点名字串*/
typedefintAdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];/*邻接距阵*/
/*链表的结点结构信息*/
typedefstructArcNode{/*定义边结点*/
intadjvex;/*该弧指向的顶点的位置*/
intweight;/*该弧的权重*/
structArcNode*nextarc;/*指向下一条弧的指针*/
}ArcNode;
/*表头向量的结点结构信息*/
typedefstructVNode{
VertexTypedata;/*顶点信息*/
ArcNode*firstarc;/*指向第一条依附该顶点的弧的指针*/
}VNode,AdjList[MAX_VERTEX_NUM];//定义图结点
/*链表带权图的结构信息*/
typedefstruct{
AdjListvertices;/*表头向量*/
intvexnum,arcnum;//顶点数和弧数
}ALGraph;//定义图
/*矩阵带权图的结构信息*/
structMGraph
{Vertexvexs[MAX_VERTEX_NUM];/*顶点向量*/
AdjMatrixarcs;/*邻接距阵*/
intvexnum,arcnum;/*顶点数和弧数*/
};
structarry
{VertexTypeadjvex;
intlowcost;
}closedge[MAX_VERTEX_NUM];
intLocateVex(MGraphG,Vertexu)//矩阵求点u所在位置
{inti;
for(i=0;i if(strcmp(u,G.vexs[i])==0) returni; return-1; } intLocateVe(ALGraphG,VertexTypeu)//链表求出点u所在位置 {inti; for(i=0;i if(strcmp(G.vertices[i].data,u)==0) returni; return-1; } /*============================================*/ /*===========邻接矩阵的克鲁斯卡尔算法=========*/ /*============================================*/ voidCreateGraph(MGraph&G)//建立带权邻接矩阵结构 {inti,j,k,w; Vertexva,vb; printf("请输入无向网G的顶点数和边数(分别以空格为分隔): \n"); scanf("%d%d",&G.vexnum,&G.arcnum); printf("请输入%d个顶点的值: \n",G.vexnum,MAX_NAME); for(i=0;i scanf("%s",G.vexs[i]); for(i=0;i for(j=0;j G.arcs[i][j]=0x7fffffff; printf("请输入%d条边各自的起点,终点,权值(分别用空格分隔): \n",G.arcnum); for(k=0;k {scanf("%s%s%d",va,vb,&w); i=LocateVex(G,va); j=LocateVex(G,vb); G.arcs[i][j]=G.arcs[j][i]=w;/*对称*/ } } /*邻接矩阵的克鲁斯卡尔算法*/ voidkruskal(MGraphG) {intset[MAX_VERTEX_NUM],i,j;/*set数组用来判断两个点是否在同一个集合里*/ intk=0,a=0,b=0,min=G.arcs[a][b]; for(i=0;i set[i]=i; printf("最小代价生成树的各条边为: \n"); while(k {for(i=0;i for(j=i+1;j if(G.arcs[i][j] { min=G.arcs[i][j]; a=i; b=j; } min=G.arcs[a][b]=0x7fffffff;//将最小权值改成最大值 if(set[a]! =set[b])/*若a、b两个点不在同一集合里,则输出a、b之间的边*/ {/*ints1=set[b];*/ printf("%s-%s\n",G.vexs[a],G.vexs[b]); k++; for(i=0;i if(set[i]==set[b]/*s1*/) set[i]=set[a]; } } } /*邻接矩阵的克鲁斯卡尔算法*/ voidk1(){ MGraphg; CreateGraph(g); kruskal(g); } /*============================================*/ /*===========邻接链表的克鲁斯卡尔算法=========*/ /*============================================*/ voidCreateGraph(ALGraph&G){//邻接链表创建带权图 inti,j,k,w; VertexTypeva,vb; printf("请输入顶点数,边数(请用空格分开): \n");/*输入顶点数、弧数*/ scanf("%d%d",&G.vexnum,&G.arcnum); printf("请输入各顶点的值: \n"); for(i=0;i scanf("%s",G.vertices[i].data); for(i=0;i G.vertices[i].firstarc=NULL; printf("请输入各边的起点,终点,权值(分别用空格分开): \n"); for(k=0;k scanf("%s%s%d",va,vb,&w); i=LocateVe(G,va);/*确定va、vb的位置*/ j=LocateVe(G,vb); ArcNode*p=(ArcNode*)malloc(sizeof(ArcNode));//申请一个结点空间 p->adjvex=j;//初始化 p->weight=w; p->nextarc=G.vertices[i].firstarc;//插表头 G.vertices[i].firstarc=p; ArcNode*q=(ArcNode*)malloc(sizeof(ArcNode)); q->adjvex=i; q->weight=w; q->nextarc=G.vertices[j].firstarc; G.vertices[j].firstarc=q; } } /*邻接链表的克鲁斯卡尔算法*/ voidkruskal2(ALGraphG){ inti,j,min=0x7fffffff,k=0;//min用于记录最小权值 intset[MAX_VERTEX_NUM];//用于判断两个点是否在同一集合里 ArcNode*p,*q,*s; for(i=0;i while(k for(i=0;i if(G.vertices[i].firstarc! =NULL){//若第i+1个点没有领边,则下一循环 for(p=G.vertices[i].firstarc;p! =NULL;p=p->nextarc)//查找最小权值的边 if(p->weight min=p->weight; q=p; j=i; } } } if(G.vertices[j].firstarc==q)G.vertices[j].firstarc=q->nextarc;//if-else用于删除最小权值的边 else{ for(p=G.vertices[j].firstarc;p! =q;p=p->nextarc)s=p; s->nextarc=q->nextarc; } if(set[j]! =set[q->adjvex]){//判断两点是否在同一集合,若不在,则输出这条边printf("(%s,%s)%d\n",G.vertices[j].data,G.vertices[q->adjvex].data,q->weight); k++; /*ints2=set[j];*/ for(i=0;i if(set[i]==set[j]/*s2*/) set[i]=set[q->adjvex]; } min=0x7fffffff;//将min置为最大值 } } voidk2(){ ALGraphG; CreateGraph(G); kruskal2(G); } /*============================================*/ /*===========邻接矩阵的普里姆算法=========*/ /*============================================*/ intminimum2(MGraphG,structarrywq[]) {inti,j; for(i=0;i if(wq[i].lowcost! =0&&wq[i].lowcost! =0x7fffffff) break;j=i; for(i=0;i if(wq[j].lowcost>wq[i].lowcost&&wq[i].lowcost! =0) j=i; returnj; } voidMiniSpanTree_PRIM2(MGraphG,VertexTypeu) {inti,j,k; k=LocateVex(G,u); for(j=0;j if(j! =k) {strcpy(closedge[j].adjvex,u); closedge[j].lowcost=G.arcs[k][j];} } closedge[k].lowcost=0; for(i=1;i k=minimum2(G,closedge); closedge[k].lowcost=0; printf("%s%s",closedge[k].adjvex,G.vexs[k]); for(j=0;j if(G.arcs[k][j] =0){ strcpy(closedge[j].adjvex,G.vexs[k]); closedge[j].lowcost=G.arcs[k][j]; } } } voidk3(){ MGraphg; CreateGraph(g); MiniSpanTree_PRIM2(g,"v1"); } /*============================================*/ /*===========邻接表的普里姆算法=========*/ /*============================================*/ intminimum1(ALGraphG,structarrywq[]) { inti,j; for(i=0;i if(wq[i].lowcost! =0&&wq[i].lowcost! =0x7fffffff) break;j=i; for(i=0;i if(wq[j].lowcost>wq[i].lowcost&&wq[i].lowcost! =0) j=i; returnj; } voidMiniSpanTree_PRIM1(ALGraphG,VertexTypeu) {inti,j,k;ArcNode*p; p=(ArcNode*)malloc(sizeof(ArcNode)); k=LocateVe(G,u); for(j=0;j closedge[j].lowcost=0x7fffffff; for(j=0;j {if(strcmp(G.vertices[j].data,u)==0) { for(p=G.vertices[k].firstarc;p! =NULL;p=p->nextarc) {closedge[p->adjvex].lowcost=p->weight; strcpy(closedge[p->adjvex].adjvex,u);}//for break; }//if }//for closedge[k].lowcost=0; for(i=1;i k=minimum1(G,closedge); closedge[k].lowcost=0; printf("%s%s",closedge[k].adjvex,G.vertices[k].data); for(j=0;j for(p=G.vertices[k].firstarc;p! =NULL;p=p->nextarc) if(p->weight {closedge[j].lowcost=p->weight; strcpy(closedge[j].adjvex,G.vertices[k].data);} }} voidk4(){ ALGraphG; CreateGraph(G); MiniSpanTree_PRIM1(G,"v1"); } intmain() {intcord; do {printf("\n===================================="); printf("\n主菜单"); printf("\n1.邻接矩阵实现克鲁斯算法"); printf("\n2.邻接链表实现克鲁斯算法"); printf("\n3.邻接矩阵实现普里姆算法"); printf("\n4.邻接链表实现普里姆算法"); printf("\n5.退出程序"); printf("\n===================================="); printf("\n请输入您的选择(1,2,3,4,5)cord="); scanf("%d",&cord); switch(cord) { case1: k1();break; case2: k2();break; case3: k3();break; case4: k4();break; case5: exit(0); } }while(cord<=5); system("pause"); } 八、测试情况 程序的测试结果如下: 邻接矩阵实现克鲁斯卡尔运行结果如下 邻接链表实现克鲁斯卡尔如下 邻接矩阵实现普利姆算法如下 邻接链表实现普利姆算法如下 人工验证,都正确 九、参考文献 1、严蔚敏,《数据结构C语言》,清华大学出版社。 2、谭浩强,《c语言程序设计》,清华大学出版社。 小结 通过本次课程设计,我学到了很多。 要写好一个程序必须弄清他的最基本的思路,除此之外要有算法思路,会写一些基本函数,程序不是一个非要一个主要的函数或者程序要写完,最好有几个函数组成,以便于利用。 编程不像做其它事,它要求编程人员有非常缜密的思维,很好的整体把握能力和很好的调试程序的能力等。 决定程序成功与否的往往既是有程序的整体思路和整体算法,也要特别注重细节,一个程序没有整体思路和整体算法是写不出来的,但是细节错误往往也是程序成功的观念,小细节的错误导致运行不成功,结果错误,感觉所有的功夫都白费了,我在此次课程设计中深有体会。 编程不是轻而易举的,必须要考虑什么储存结构更适合那个算法,本次就用邻接矩阵和邻接表,而没用十字链表,十字链表不合适,而且它的操作相对比较复杂,在小程序中没有优势,还有,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 路径 算法 数据结构 课程设计