目录1 概述 (2)1.1 问题描述 (2)1.2 实现意义 (2)2 系统分析 (2)2.1 需求分析 (2)2.1.1程序的功能 (2)2.1.2输入输出的要求 (2)2.2 设计思想 (2)2.3 设计要求 (3)3 概要设计 (3)3.1建立图的存储结构 (3)3.2 单源最短路径 (3)3.3 任意一对顶点间最短路径 (4)4 详细设计 (4)4.1 用邻接矩阵构造图结构函数CreateMGraph() (4)4.2 费洛伊德Floyd() (5)4.3 迪杰斯特拉Dijkstra() (5)4.4 主要函数流程图及其函数调用 (6)4.4.1 主要函数流程图 (6)4.4.2 一个城市到其他城市的路径调用 (7)4.4.3 任意两个城市之间路径调用 (7)5 运行与测试 (7)5.1 有向图存储结构的建立模块的输出 (8)5.2 单源路径迪杰斯特拉算法模块的输出 (9)5.3 费洛伊德算法模块的输出 (9)6 总结与心得 (9)参考文献 (10)附录 (10)1 概述1.1 问题描述在交通网络非常发达,交通工具和交通方式不断更新的今天,人们在出差、旅游或做其它出行时,不仅关心节省费用,而且对里程和所需时间等问题也感兴趣。
对于这样一个人们关心的问题,可用一个图结构来表示交通网络系统,利用计算机建立一个交通咨询系统。
图中顶点表示城市之间的交通关系。
这个交通系统可以回答旅客提出的各种问题。
比如任意一个城市到其他城市的最短路径,任意两个城市之间的最短路径问题。
1.2 实现意义便于人们的日常出行,且更好地满足了用户的出行需求。
这种最短路径问题的计算方法既简单又便于实现,同时大大提高了计算机的运行速率。
2 系统分析2.1 需求分析2.1.1程序的功能(1)用户自己可以建立不同的路径之间的关系网(2)可以查询某个城市到达其余各城市的最短路径。
(3)可以任一查询两个城市之间的最短路径。
2.1.2输入输出的要求在刚进入主界面后系统提示输入建立交通网络储存结构,输入顶点个数和和边数为整数不能输入其他字符,随后系统提示输入边与边之间的关系分别为i,j,w表示边之间的距离。
然后进入查询页面,输入整数1,2,0分别表示你所要查询的功能:一个城市至其他所有城市的最短路径查询、任意两个城市之间的最短路径查询、退出程序。
不能输入其他字符否则不能执行操作。
在整个操作都是用整数表示城市。
2.2 设计思想用邻接矩阵来存储交通网络图的信息,运用迪杰斯特拉算法实现图上单源最短路径问题,然后运用费洛伊德算法实现图中任意一对顶点间最短路径问题,这样就会实现交通咨询系统设计的问题。
2.3 设计要求该交通咨询系统要完成城市网络图的存储,并要实现求任意一个城市顶点到其他城市顶点的最短路径问题,还要实现任意两个城市顶点间的最短路径问题。
故设计要分成三部分,一是建立交通网络图的存储结构;二是解决单源路径问题;最后再实现两个城市之间的最短路径问题。
3 概要设计3.1建立图的存储结构首先要定义交通图的存储结构。
邻接矩阵是表示图形中顶点之间相邻关系的矩阵。
设G=(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下定义n阶方阵。
A[i,j]= W i,j 若(v i,v j)或<v i,v j>€E(G);0或∞,当不满足上述条件时。
一个图的邻接矩阵表示是唯一的。
图的邻接矩阵表示,除了需要用一个二维数组存储顶点之间相邻关系的邻接矩阵外,通常还需要使用一个具有n个元素的一维数组来存储顶点信息,其中下表为i的元素存储顶点v的信息。
因此,图的邻接矩阵的存储结构定义如下:#define MVNum 50 //最大顶点数typedef struct{VertexType vexs[MvNum];Adjmatrix arcs[MVNum][MVNum];}MGraph;3.2 单源最短路径单源路径问题:即已知有向图(带权),我们希望找出从某个源点S€V到G中其余各顶点的最短路径。
为了叙述方便,我们把路径上的开始点称为源点,路径的最后一个顶点称为终点。
迪杰斯特拉算法求最短路径的实现思想:设有向图G=(V,E),其中,V={1,2,…,n},cost是表示G的邻接矩阵,cost[i][j]表示有向边<i,j>的权。
若不存在有向边<i,j>,则cost[i][j]的权为无穷大(这里取值为32767)。
设S是一个集合,其中的每个元素表示一个顶点,从源点到这些顶点的最短距离已近求出。
设顶点v1为源点,集合S的初态只包含顶点v1。
数组dist记录从源点到其他各顶点当前的最短距离,其初值为dist[i]= cost[v1][i],i=1,2,...,n。
从S之处的顶点集合V-S中选出一个顶点w,使dist[w]的值最小。
于是从源点到达w 只通过s中的顶点,把w加入集合S中,调整dist中记录的源点到V-S中每个顶点v的距离:从原来的dist[v]和dist[w]+cost[w][v]中选择较小的值作为新的dist[v]。
重复上述过程,直到S中包含V中其余顶点的最短路径。
最终结果是:S记录了从源点到该顶点存在最短路径的顶点集合,数组dist记录了从源点到V中其余各顶点之间的最短路径,path是最短路径的路径数组,其中path[i]表示从源点到顶点i之间的最短路径的前驱顶点。
迪杰斯特拉算法用自然语言描述如下:初始化S和D,置空最短路径终点集,置初始的最短路径值;S[v1]=TRUE; D[v1]=0; //S集初始时只有原点,源点到源点的距离为0;while(S集中顶点数<n){开始循环,每次求得v1到某个v顶点的最短路径,并加v到S集中;S[v]=TRUE;更新当前最短路径及距离;}3.3 任意一对顶点间最短路径任意顶点对之间的最短路径问题,是对于给定的有向网络图G=(V,E),要对G中任意一对顶点有序对“v,w(v≠w)”,找出v到w的最短路径。
对此问题有两种处理方法:方法一:依次把有向网络图中的每个顶点作为源点,重复执行前面讨论的迪杰斯特拉算法n次,即可求得每对之间的最短路径。
方法二(费洛伊德算法):其基本思想是:假设求从顶点v i到v j的最短路径。
如果从v i到v j存在一条长度为arcs[i][j]的路径,该路径不一定是最短路径,还需要进行n次试探。
首先考虑路径<v i,v1>和<v1,v j>的路径是否存在。
如果存在,则比较路径<v i,v j>和<v i,v1,v j>的路径长度,取长度较短者为当前所求得的最短路径。
该路径是中间顶点序号不大于1的最短路径。
其次,考虑从v i到v j是否包含有顶点v2为中间顶点的路径<v i,…,v2,…,v j>,若没有,则说明从v i到v j的当前最短路径就是前一步求出的;若有,那么<v i,…,v2,…,v j>可分解为<v i,…,v2>和<v2,…,v j>,而这两条路径是前一次找到的中间点序号不大于1的最短路径,将这两条路径长度相加就得到路径<v i,…,v2,…,v j>的长度。
将该长度与前一次中求得的从v i到v j的中间顶点序号不大于2的最短路径。
依次类推……直至顶点v n加入当前从v i到v j的最短路径后,选出v i到v j 的中间顶点序号不大于n的最短路径为止。
由于图G中顶点序号不大于n,所以v i到v j的中间顶点序号不大于n的最短路径,已考虑了所有顶点作为中间顶点的可能性,因此,它就是v i到v j的最短路径。
4 详细设计4.1 用邻接矩阵构造图结构函数CreateMGraph()其中vexs[MVNum]保存顶点信息,arcs[MVNum][MVNum]用于保存边与边之间的信息。
在构建时通过输入的边数i,j作为矩阵的行、列确定顶点的出度和入度。
用邻接矩阵方法存储图,很容易确定图的任意两个顶点是否是有边相连,因此用邻接矩阵对有利于后面费洛伊德算法和迪杰斯特拉算法。
数据类型定义:typedef struct{VertexType vexs[MVNum];Adjmatrix arcs[MVNum][MVNum];}MGraph;邻接矩阵的程序代码:for(k=1;k<=e;k++) //读入e条边建立邻接矩阵{ printf(" 第%d条边的信息:",k);scanf("%d,%d,%d",&i,&j,&w);G->arcs[i][j]=w;G->arcs[j][i]=w;}4.2 费洛伊德Floyd()费洛伊德算法对求任意两个顶点之间的路径较优。
用邻接矩阵保存图存储后,另外需要存一个二维数组A存放当前顶点之间的最短路径长度。
分量A[i][j]表示当前顶点i到j的最短路径长度。
费洛伊德算法的基本思维是递推产生一个矩阵序列A0,A1,A2,….Ak,…An,其中Ak[i][j]表示从顶点到vi到顶点vj 的路径上所经过的顶点编号不大于k的最短路径长度。
A[i][j]=cost[i][j]A(k+1)[i][j]=min{Ak[i][j],Ak[i+1][k+1]+Ak[k+1][j]}费洛伊德主要算法,若Ak[i][j]已求出,顶点i到顶点k+1的路径长度为Ak[i][k+1],顶点路径长度为Ak[i][j],顶点k+1到顶点j的路径长度为Ak[k+1][j],如果此时Ak[i][k+1]+Ak[k+1][j]< Ak[i][j],则将原来的顶点i到顶点j的路径改为顶点,否则不需要修改顶点i到j的路径。
for(k=1;k<=n;k++){for(i=1;i<=n;i++)for(j=1;j<=n;j++){ if(D[i][k]+D[k][j]<D[i][j]){D[i][j]=D[i][k]+D[k][j]; //修改长度P[i][j]=P[i][k];}}}4.3 迪杰斯特拉Dijkstra()迪杰斯特拉算法对求一个顶到到其他所有顶点的路径较优。
初始时,S中只包含原点,顶点v到自己的距离为0,D中包含出v外的其他顶点,v到D中顶点u的距离为边上的权值。
从D中选取一个顶点k,顶点v到顶点k的距离最小,然后把顶点k加入到S中,该选定的距离就是v到k的最短路径长度。
以顶点k为新考虑的中间点,修改顶点v到U中各顶点的距离,若从原点v到顶点u的距离比原来的距离(不经过k)的距离看,短,则修改顶点u的距离值,修改后的距离值为顶点v到顶点k的距离加上边<k,u>上的权。
迪杰斯特拉的算法:D2[v1]=0;S[v1]=1; //原点编号放入s中for(i=2;i<n;i++){ min=IDF;for(w=1;w<=n;w++)if(!S[w]&&D2[w]<min){v=w;min=D2[w];}S[v]=1; //修改顶点u放入s中for(w=1;w<=n;w++)if(!S[w]&&(D2[v]+G->arcs[v][w]<D2[w])){D2[w]=D2[v]+G->arcs[v][w];P2[w]=v;}}4.4 主要函数流程图及其函数调用4.4.1 主要函数流程图图4-4-1 主要函数流程图4.4.2 一个城市到其他城市的路径调用4-4-2 调用dijkstra()4.4.3 任意两个城市之间路径调用4-4-3 调用floyd()5 运行与测试求有向图的最短路径:如图5 所示的有向图,求顶点a到其余顶点的最短路径;分别求顶点b到顶点d之间以及顶点a到顶点d的最短路径。