求解最短路径的Dijkstra算法.docx
《求解最短路径的Dijkstra算法.docx》由会员分享,可在线阅读,更多相关《求解最短路径的Dijkstra算法.docx(16页珍藏版)》请在冰豆网上搜索。
求解最短路径的Dijkstra算法
一、问题分析与任务定义
本题主要是利用Dijkstra算法来求解顶点之间最短路径,其中包括如下几个待解决的问题:
1问题分析
选择合适的结构表示图主要包括:
用Dijkstra算法实现起来更要容易;时间复杂度小;自己可以熟练应用。
Dijstra算法的实现所应涉及到的各参数及变量:
顶点的编号;各边权的初使化;如何求出从顶点到其他各点的最短距离;最短距离长度的求取等问题。
2任务定义
对任意图,选择合适的数据结构表示图,在此基础上实现求解最短路径的Dijkstra算法。
要求:
对所设计的图的数据结构,提供必要的基本功能。
在带权的有向图中源点到终点的多条路径中寻找出一条各边权植之和最小的路径,即最短路径。
对任务的理解考虑设计的图结构是否具备必要的基本功能,具有实际的应用;图的邻接矩阵如何实现交互式;如何将输入的邻接矩阵溶入到dijstra算法中去。
需要解决什么样的实际问题。
并且能够将程序与实际问题相结合,能够处理一般的最短路径问题。
二、概要设计和数据结构的选择
按路径长度递增的顺序产生最短路径。
通过以上对问题的分析和任务的理解,设计出一个大体的模块和程序流程。
1程序中涉及到的结构体及子函数:
1.1结构体:
本程序设计使用了以下结构体:
structvertex
{intnum;//顶点编号
intdata;//顶点信息
};//顶点类型
typedefstructgraph
{
intn;//图中顶点个数
inte;//图中边的个数
structvertexvexs[MAXVEX];//顶点集合
intedges[MAXVEX][MAXVEX];//边的集合
}AdjMaxix;//图的邻接矩阵类型
1.2子函数:
设计本程序需分成几个模块,要用到以下几个子函数:
AdjMaxixcreatmgraph()//通过用户交互产生一个有向图的邻接矩阵;
voiddispmgraph(AdjMaxixadj)//用于输出一个有向图的邻接矩阵;
voidppath(intpath[],inti,intv0);
//选择输出一条最短路径
voidDisPath(intdist[],intpath[],ints[],intn,intv0)
//用path计算最短路径
voidDijkstra(AdjMaxixg,intv0)//Dijkstra算法
voidchange(intnum)//用于替换顶点编号
1.3结构图与流程图
1.3.1结构图
图1结构图
1.3.2流程图
yes
图2程序流程图
三、详细设计和编码
这里设计用邻接矩阵解决实际生活中城市间往返最短路径问题。
1算法思想
把图中顶点集合分成两组,第一组为集合S,存放已求出其最短路径的顶点,第二组为尚未确定最短路径的顶点集合是V-S(用U表示),其中V为网中所有顶点集合。
在这里我们设计一个有向图G=(V,E)为G地区的交通图。
1.1在这个图中,V=(1,2,……,N)代表各个城市。
edges是表示G的邻接矩阵,edges[I][j]表示有向边的权,这里的权值代表城市间距离。
若不存在有向边的权,则edges[I][j]的权为无穷大(可取值为INF=32570)。
设S为一个集合,其中的每个元素表示一个城市,求出从源点(自定义)城市到这些顶点城市的最短距离。
S的初态只包含顶点V0。
数组dist记录从V0到其他各城市当前的最短距离,其初值dist[I]=edges[V0][I]。
从S之外的顶点集合V-S中选出一个城市u。
使dist[w]的值最小。
于是从源点到达u只通过S中的城市,把u加入集合S中调整dist中记录的从源点到V-S中每个城市V的距离:
从原来的dist[v]和dist[w]+edges[w][v]中选择较小的值作为新的dist[v]。
重复上述过程,直到S中包含V中其余顶点的最短路径。
1.2算法描述:
voidDijkstra(AdjMaxixg,intv0)
{intdist[MAXVEX],path[MAXVEX];
ints[MAXVEX];
intmindis,i,j,u,n=g.n;
for(i=0;i{
dist[i]=g.edges[v0][i];
s[i]=0;
if(g.edges[v0][i]path[i]=v0;
else
path[i]=-1;
}
s[v0]=1;path[v0]=0;
for(i=0;i{
mindis=INF;
u=-1;
for(j=0;jif(s[j]==0&&dist[j]{
u=j;
mindis=dist[j];
}
s[u]=1;
for(j=0;jif(s[j]==0)
if(g.edges[u][j]{
dist[j]=dist[u]+g.edges[u][j];
path[j]=u;
}
2采用邻接矩阵的存储结构
2.1图的邻接矩阵可以使用一个二维数组存储顶点之间相邻关系的邻接矩阵,和一个具有N个元素的一维数组存储顶点信息,其中下标为i的元素存储顶点Vi的信息。
2.2算法描述:
voidCreatdl(vexlistGV,adjmatrixGA,intn,inte)
{
intI,j,k,w;
cout<<”输入”<for(I=0;Icin>>GV[I];
for(I=0;Ifor(j=o;j{if(I==j)
GA[I][j]=o;
else
GA[I][j]=MaxValue;
}
cout<<”输入”<for(k=1;k<=e;k++)
{cin>>I>>j>>w;
GA[I][j]=GA[I][j]=w;
}
}
四、上机调试
对设计实现的回顾讨论和分析;算法的时、空性能分析和改进设想,经验和体会等。
1调试中遇到的问题与解决方法
1.1在进行输入输出语句的调试时,系统提示无法识别函数,缺少头文件;
1.2出现重大错误,多达数百条错误,着实郁闷了一阵;很多标点符号是在中文输入法状态下输入,造成系统无法识别,改掉后错误消失;如 switch语句,在每条选择语句后,缺少break(),错误;
1.3函数方法使用有误,无法通过;在赋实参时,对于变化的实参只需赋初值,子函数也可以调用子函数;
1.4困惑很久的调用子函数问题,在赋实参时找不到实参;用switch语句进行相关选择代换,成功。
1.5连系实际问题上,int型与char型的替换上不知道用什么函数实现;
2设计体会
对C语言的使用不是很熟练,造成自己浪费很多时间在复习C语言,如:
结构体的使用,不能灵活应用do,while(),switch()语句等;调用子函数问题上,子函数之间错综复杂的调用和实参,形参的赋值让自己很是迷惑,三天时间,也许更多时间里,都是在研究怎样调用子函数。
虽然最后基本是完成了教授布置下来的课程设计,但是还是有不尽人意的地方:
结点的插入,删除,路径的实际化最终由于时间问题没能解决,很遗憾。
程序缺乏人性化设计,估计第一次使用本程序的人会很迷茫。
3时间空间复杂度的计算
利用Dijkstra算法求解最短路径时,求每一对顶点之间的最短路径的一种方法是反复执行n次Dijkstra算法,每次执行以一个顶点为源点,求得从该顶点到其它各顶点的最短路径;其时间复杂度为O(n3)。
其空间的复杂度为o(n)。
五、用户使用说明
本程序主要是用来计算从某一点到其他各点的最短路径长度,第一次使用可能会有点迷茫,但是它却是本人两周来的血汗,如有不便请原谅。
下面描述该使用方法:
程序会在一开始让用户输入结点数,线路数,然后输入相关结点信息,有城市名字(只能使用英文名称),线路长度,起点城市,终点城市。
接下来都由计算机完成。
结果会输出源点到各城市间的长度。
六、测试结果
输入数据:
输入城市数为:
4
输入城市线路为:
4
然后输入城市信息(这里每个数字代表1A地2B地3C地4D地):
输入第一个城市信息:
1
输入第二个城市信息:
2
输入第三个城市信息:
3
输入第四个城市信息:
4
输入第一条线路的起点:
1,终点:
3
线路长度为:
56
输入第二条线路的起点:
2,终点:
3
线路长度为:
78
输入第三条线路的起点:
1,终点:
2
线路长度为:
89
输入第三条线路的起点:
3,终点:
4
线路长度为:
99
下面是结果截图:
图3输入所有城市信息
图4输出最短路径
七、参考书目
1徐孝凯数据结构实用教程,清华大学出版社,1999年12月第1版。
2谭浩强《c语言程序设计》,清华大学出版社。
3李春葆数据结构习题与解析,清华大学出版社,2004年2月第2版。
4数据结构-—C++语言描述,人民邮电出版社,2005年三月第1版。
5数据结构(C语言描述),清华大学出版社,2004年十月第1版。
八、附录:
带注释的源程序
/*————————————————————————————-----------*//**/
/*用Dijkstra算法求出有向图中某个源点到其他各顶点的最短路径长度*/
/**/
/*————————————————————————————-----------*/
#include
#include
#include
#include
#defineINF32767
#defineMAXVEX100
#defineMAX12
structvertex
{intnum;//顶点编号
intdata;//顶点的信息
};//顶点类型
typedefstructgraph
{
intn;
inte;//图中顶点的个数和边的个数
structvertexvexs[MAXVEX];//顶点集合
intedges[MAXVEX][MAXVEX];//边的集合
}AdjMaxix;//图的邻接矩阵类型
AdjMaxixcreatmgraph()//通过用户交互产生一个有向图的邻接矩阵
{
inti,j,k,w,n,e;
intb,t;
AdjMaxixadj;
cout<<"输入城市数:
";//对图的所有信息进行逐步输入
cin>>n;
while(n>MAX||n<0)
{
cout<<"城市个数不正确!
请重新输入!
"<cin>>n;
}
cout<<"输入城市线路数:
";
cin>>e;
adj.n=n;
adj.e=e;
cout<<"输入城市信息:
\n";
for(i=0;i{
cout<<"第"<
";
cin>>adj.vexs[i].data;
adj.vexs[i].num=i;
}
for(i=0;ifor(j=0;jadj.edges[i][j]=0;
for(k=0;k{
cout<<"第"<"<cout<<"起点:
";
cin>>b;
cout<<"终点:
";
cin>>t;
cout<<"线路长度为(Km):
";
cin>>w;
i=0;
while(i=b)
i++;
if(i>=n)
{
cout<<"输入的起点城市不存在!
\n";
abort();
}
j=0;
while(j=t)
j++;
if(j>=n)
{
cout<<"输入的终点不存在!
\n";
abort();
}
adj.edges[i][j]=w;
}
return(adj);
}
voiddispmgraph(AdjMaxixadj)//用于输出一个有向图的邻接矩阵
{
inti,j,n,e;
n=adj.n;
e=adj.e;
cout<<"输出线路的矩阵表示:
"<cout<<"";
for(i=-1;iprintf("%6d",i);
printf("\n");
cout<for(i=0;i{
printf("%6d",i);
for(j=0;jif(adj.edges[i][j]==0)
printf("%6s","∞");
else
printf("%6d",adj.edges[i][j]);
cout<}
}
voidppath(intpath[],inti,intv0)
{
intk;
k=path[i];
if(k==v0)
return;
ppath(path,k,v0);
printf("%d,",k);
}
voidDisPath(intdist[],intpath[],ints[],intn,intv0)
{
inti;//用path计算最短路径
printf("path:
");//输出path值
for(i=0;iprintf("%3d",path[i]);
printf("\n");
for(i=0;iif(s[i]==1&&i!
=v0)
{
printf("从%d到%d的最短路径为:
",v0,i);
printf("%d,",v0);
ppath(path,i,v0);
printf("%d\n",i);
}
else
printf("从%d到%d不存在路径\n",v0,i);
}
voidDijkstra(AdjMaxixg,intv0)
{
intdist[MAXVEX],path[MAXVEX];
ints[MAXVEX];
intmindis,i,j,u,n=g.n;
for(i=0;i{
dist[i]=g.edges[v0][i];//距离初始化
s[i]=0;//s[]置空
if(g.edges[v0][i]path[i]=v0;
else
path[i]=-1;
}
s[v0]=1;path[v0]=0;//源点编号v0放入s中
for(i=0;i{
mindis=INF;
u=-1;
for(j=0;jif(s[j]==0&&dist[j]{
u=j;
mindis=dist[j];
}
s[u]=1;//顶点u加入s中
for(j=0;jif(s[j]==0)
if(g.edges[u][j]{
dist[j]=dist[u]+g.edges[u][j];
path[j]=u;
}
}
printf("输出最短路径:
\n");
DisPath(dist,path,s,n,v0);//输出最短路径
}
voidchange(intnum)//选择语句用于替换顶点值,输出名称
{
switch(num)
{case1:
printf("A地");break;
case2:
printf("B地");break;
case3:
printf("C地");break;
case4:
printf("D地");break;
case5:
printf("E地");break;
case6:
printf("F地");break;
case7:
printf("G地");break;
case8:
printf("H地");break;
case9:
printf("I地");break;
case10:
printf("J地");break;
case11:
printf("K地");break;
case12:
printf("L地");break;
}
}
voidmain()
{inti;charx;
do//循环函数,使程序可以循环使用
{
printf("下面每个数字代表一个城市,请输入相应的代码,第一个输入的是出发地!
\n\n");
printf("1A地2B地3C地4D地5E地6F地\n7G地8H地9I地10J地11K地12L地\n");
AdjMaxixg=creatmgraph();
intn=g.n;
dispmgraph(g);
Dijkstra(g,0);
printf("从出发地到各地最短路程长度如下,若长度为0则表示无法到达或在本地:
\n");
for(i=0;i{change(g.vexs[0].data);
printf("----->");
change(g.vexs[i].data);
printf("%3dKm\n",g.edges[0][i]);
}
printf("\n\n谢谢使用WOW路径查讯系统,如果想退出请输入'#',任意键继续:
");
scanf("%c",&x);
printf("\n");
}
while(x!
='#');//输入n结束程序
}
九、指导教师评语