完整word版数据结构课程设计最短路径.docx

上传人:b****6 文档编号:4968848 上传时间:2022-12-12 格式:DOCX 页数:34 大小:144.88KB
下载 相关 举报
完整word版数据结构课程设计最短路径.docx_第1页
第1页 / 共34页
完整word版数据结构课程设计最短路径.docx_第2页
第2页 / 共34页
完整word版数据结构课程设计最短路径.docx_第3页
第3页 / 共34页
完整word版数据结构课程设计最短路径.docx_第4页
第4页 / 共34页
完整word版数据结构课程设计最短路径.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

完整word版数据结构课程设计最短路径.docx

《完整word版数据结构课程设计最短路径.docx》由会员分享,可在线阅读,更多相关《完整word版数据结构课程设计最短路径.docx(34页珍藏版)》请在冰豆网上搜索。

完整word版数据结构课程设计最短路径.docx

完整word版数据结构课程设计最短路径

数据结构课程设计

题目名称:

最短路径

计算机科学与技术学院

1、需求分析

(1)题目:

最短路径

实现图的输入,选择合适的结构表示图,在此基础上实现求解最短路径的算法,可以从任意一点求最短路径,学生必须准备多组测试数据,并设计清晰易懂的输入输出界面,

要求:

如何用多种数据结构来求解问题。

同时要求实现对应数据结构的所有基本操作。

(2)程序的输入与输出:

要求用多种数据结构求解问题,也就是要用邻接表与邻接矩阵实现最短路径的算法,需要有多组输入输出,

(a)输入的形式和输入值的范围:

输入的形式为整型

1.先输入共需要创建几次图

2.再分别输入边数和顶点数(范围:

1~100)

3.输入1和2选择是否为有向图图(1为有向,2为无向)

4.对应每条边输入起点和终点下标,以及对这条边的权值(最大的权值为100)。

5.输入在邻接表的基础上输入深度与广度优先搜索的起点

6.我们输入求各种最短路径起点和终点

(b)输出的形式;

1.输出所建立的邻接表(表结点后面的括号是头结点与表结点的权值)

2.输出DFS和BFS的结果

3.输出该图不带权值的最短路径与路径

4.接下来输入起点和终点,求带权值的最短路径也就是Dijstra算法,输出长度并给出路径

5.前面都是用邻接表实现的各种算法,接下来的Floyd算法就用矩阵实现,于是直接邻接表转矩阵输出

6.用Floyd算法求出图的多源最短路径,给出起点终点输出最短路径长度,接着便到了第二次创建图,直至循环结束。

 

(3)程序的功能:

求给出带权图的任意两点,输出最短路径长度并给出其最短路径所经过的顶点。

在实际应用中可以将交通网络化成带权的图,图中顶点表示城市,边代表城市之间的公路,边上的权值表示公路的长度。

这样可以发现两个地方之间有无公路可连,在几条公路可通的情况下,可以找到那条路径最短。

也就是现在地图app中的功能。

(4)测试数据:

包括正确的输入及其输出结果和含有错误的输入及其输出结果。

在有向图中输入错误的数据(顶点与顶点方向相反),会输出逆向信息。

 

2、概要设计

1.主程序流程

(a)主程序首先多组输入一个n,在n不为0的前提下循环执行

(b)调用BuildGraph()函数,创建一个图并以邻接表的形式存储

(c)BuildGraph()函数输入顶点、边数调用CreateGraph(Nv)函数,初始化一个有Nv个顶点但没有边的图,再根据结构体Edge输入每个边的信息,调用InsertEdge(Graph,E,c);函数将每条边插入到仅仅初始化的图中,完成一个图的建立,并返回一个邻接表类型的结构体

(d)主函数接到返回来的邻接表结构体,调用outL()函数,输出这个邻接表

(e)输入起点,调用DFS(Graph,v1,1);函数进行递归求解深度优先搜索并直接输出

(f)输入起点,调用BFS(Graph,v1);函数,求解广度优先搜索并直接输出

(g)输入起点、终点,调用Unweighted(Graph,v1);函数求得起点到每个点的最短路径,再用dist[v2]输出。

(h)如果dist[v2]大于0证明v1可以到达v2,调用outpath(v2)输出路径

(i)输入起点、终点,调用Dijkstra(Graph,v1);函数求得起点到每个点的最短路径,再用dist[v2]输出。

(j)如果dist[v2]小于定义的INF,证明v1可以到达v2,再次调用outpath(v2)输出路径

(k)用MGraphgra;创建一个邻接矩阵之后,调用transform(Graph);进行邻接表与邻接矩阵的转换

(l)outM(gra);函数,以二维数组的形式输出邻接矩阵

(m)调用Floyd(gra,D,pa);函数求得多源最短路径,存储在D这个二维数组中,给出起点,终点直接输出。

2.所有用到的抽象数据类型

(1)边的定义

(a)表示边的起点和终点

(b)边的权重

 

(2)邻接表的表结点的定义

(a)邻接点下标

(b)边权重

(c)指向下一个邻接点的指针

(3)邻接表的顶点表头结点的定义

(a)边表头指针

(b)存顶点的数据

(c)邻接表类型的AdjList存储邻接表的头结点

(4)邻接表对应图结点的定义

(a)顶点数

(b)边数

(c)邻接表

(5)邻接矩阵的定义

(a)顶点数

(b)边数

(c)二维数组形式的邻接矩阵

(6)BFS存数据的队列

(a)队头front标记

(b)队头rear标记

(c)存数据的数组

(7)用于输出最短路径的栈

(a)栈顶top标记

(b)存数据的数组

 

3.设计程序的各个模块(即函数)功能及设计思想

(1)CreateGraph(intVertexNum)函数

功能:

初始化一个有VertexNum个顶点但没有边的图

设计思想:

(a)根据邻接表结构体分配一块空间

(b)初始化图的顶点数和边数

(c)初始化邻接表头指针

(d)注意:

这里默认顶点编号从1开始,到Graph->Nv

(e)初始化dist[]与path[]数组

 

(2)InsertEdge(LGraphGraph,EdgeE,intc)函数

功能:

在建立的图中插入边

设计思想:

(a)输入v1,v2,建立一个v2的新的邻接点

(b)将V2插入V1的表头,用c做标志位,在调用函数时输入

(c)若c=2,表示图为无向图,还要插入边

(d)接着为V1建立新的邻接点,将V1插入V2的表头

(3)BuildGraph()函数

功能:

输入顶点和边数,定义有向图和无向图,建立图,并返回邻接表类型的指针

设计思想:

(a)读入顶点个数,调用CreateGraph(Nv)初始化有Nv个顶点但没有边的图

(b)读入边数,定义有向、无向,如果有边,建立边结点,读入边,格式为"起点终点权重",插入邻接表

(c)注意:

如果权重不是整型,Weight的读入格式要改

(4)clrv(LGraphg)函数

功能:

初始化图的访问数组Visited[]为0

设计思想:

重置被DFS和BFS修改过的visited数组

(5)DFS(LGraphGraph,VertexV,intx)函数

功能:

以V为出发点对邻接表存储的图Graph进行DFS搜索

设计思想:

(a)首先访问出发点v,并将其标记为已访问过;(b)然后依次从v出发搜索v的每个邻接点w。

若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。

(c)若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。

(d)也就是访问顶点v,从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历,重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

(6)CreateQueue()函数

功能:

初始化一个队列

设计思想:

(a)队列的front与rear分别置-1

(b)为数组分配空间

(7)AddQ(QueueQ,VertexS)函数

功能:

向队列中添加元素

设计思想:

(a)将rear位置挪一位

(b)在rear这位加入一个数

(8)DeleteQ(QueueQ)函数

功能:

队列中删除一个元素,并返回

设计思想:

(a)从队列的头出队

(b)也就是front位置加一

(c)将front这位的数据弹出

(9)IsEmpty(QueueQ)函数

功能:

判断队列是否为空

设计思想:

(a)判断front的位置与rear是否相等

(10)Unweighted(LGraphGraph,VertexS)函数

功能:

输入两点,求对应不带权值的图的最短路径

设计思想:

(a)按照递增(非递减)的顺序找出各个顶点的最短路,类似于BFS

(b)先创建空队列,MaxSize为外部定义的常数

(c)初始化源点.dist[S]=0

(d)对V的每个邻接点W->AdjV

(e)若W->AdjV未被访问过,W->AdjV到S的距离更新

(f)将V记录在S到W->AdjV的路径上

(11)BFS(LGraphGraph,VertexV)函数

功能:

向队列中添加元素

设计思想:

(a)顶点v入队列。

(b)当队列非空时则继续执行,否则算法结束。

(c)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。

(d)查找顶点v的第一个邻接顶点first。

(e)若v的邻接顶点first未被访问过的,则first入队列。

(f)继续查找顶点v的另一个新的邻接顶点first,转到步骤(e)。

(g)直到顶点v的所有未被访问过的邻接点处理完。

转到步骤(f)。

(12)clr(LGraphGraph)函数

功能:

重置dist[]数组与path[]数组

设计思想:

(a)重置最短路径的举例与路径

(13)FindMinDist(LGraphGraph,intcollected[])函数

功能:

传入一个dist[]中没有被收录(collected[]对应为-1)的数

设计思想:

(a)V从1到顶点最大的下标

(b)若V未被收录,且dist[V]更小

(c)更新最小距离更新对应顶点

(d)若找到最小dist,返回对应的顶点下标

(e)若这样的顶点不存在,返回错误标记

(14)Dijkstra(LGraphGraph,VertexS)函数

功能:

求出输入VertexS的单源最短路径

设计思想:

(a)Dijkstra算法开始采用的是一种贪心的策略,声明一个数组dist来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合T

(b)初始时,原点s的路径权重被赋为0(dis[s]=0)

(c)若对于顶点s存在能直接到达的边(s,m),则把dis[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大

(d)初始时,集合T只有顶点s。

(e)从dis数组选择最小值(贪心),则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中,OK,此时完成一个顶点,

(f)我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。

 

(g)然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点。

 

(15)transform(LGrapha)函数

功能:

邻接矩阵与邻接表转换

设计思想:

(a)分析邻接矩阵与邻接表的异同

(b)邻接表有一个头结点数组,每一个对应一串链表,跟着的是每一个顶点与邻接点相连

(c)邻接矩阵则是一个二维数组,两点有边值为权重,没有则初始化为无穷

(d)先初始化一个空的二维数组

(e)再对应邻接表每个头结点遍历其链表,将其值对应的加入到邻接矩阵中

(16)outM(MGraphgra)函数

功能:

传入邻接矩阵结构体,输出邻接矩阵

设计思想:

(a)相当于输出一个二维数组

(17)outL(LGraphGraph)函数

功能:

传入邻接表结构体,输出邻接表

设计思想:

(a)第一个循环遍历每个头结点

(b)在第一个循环中表结点的地址不为空则输出(还要输出权值)

(18)Floyd(MGraphGraph,WeightTypeD[][maxVnum],Vertexpath[][maxVnum])函数

功能:

Floyd算法求出多源最短路径

设计思想:

(a)通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入两个矩阵,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。

矩阵P中的元素b[i][j],表示顶点i到顶点j经过了b[i][j]记录的值所表示的顶点。

(b)假设图G中顶点个数为N,则需要对矩阵D和矩阵P进行N次更新。

(c)初始时,矩阵D中顶点a[i][j]的距离为顶点i到顶点j的权值

(d)如果i和j不相邻,则a[i][j]=∞,矩阵P的值为顶点b[i][j]的j的值

(e),对矩阵D进行N次更新

(f)第1次更新时,如果”a[i][j]的距离”>“a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”),则更新a[i][j]为”a[i][0]+a[0][j]”,更新b[i][j]=b[i][0]。

(g)同理,第k次更新时,如果”a[i][j]的距离”>“a[i][k-1]+a[k-1][j]”,则更新a[i][j]为”a[i][k-1]+a[k-1][j]”,

b[i][j]=b[i][k-1]。

更新N次之后,求出最短路径

(19)StrackcreateStr()函数

功能:

创建一个栈

设计思想:

(a)分配空间,top=-1

(20)push(Strackptr,intv)函数

功能:

向栈中添加元素

设计思想:

(a)top加一

(b)对应位置存为v

(21)pop(Strackptr)函数

功能:

出栈

设计思想:

(a)先将栈顶元素弹出,top减一

(22)sIsEmpty(Strackptr)函数

功能:

判断栈是否为空

设计思想:

(a)若果top=-1,为空,否则返回0

(23)outpath(intv)函数

功能:

输出最短路径

设计思想:

(a)由于存最短路径的path[]数组每位存的只是上一个顶点,所以每次查找都会不断地找到每个顶点的上级,直至path[v]=-1,会形成一个方向的路径,就要利用堆栈后进先出的特点输出。

(b)在path存的数据不为-1时,将他们全部压入栈中,再将他们全部输出

 

3、详细设计

1.程序流程图

 

D

 

2.数据类型的实现

(1)边的定义

typedefstructENode*PtrToENode;

structENode{

VertexV1,V2;/*有向边*/

WeightTypeWeight;/*权重*/

};

typedefPtrToENodeEdge;

 

(2)邻接表的表结点的定义

typedefstructAdjVNode*PtrToAdjVNode;

structAdjVNode{

VertexAdjV;/*邻接点下标*/

WeightTypeWeight;/*边权重*/

PtrToAdjVNodeNext;/*指向下一个邻接点的指针*/

};

typedefPtrToAdjVNodeANode;

(3)邻接表的顶点表头结点的定义

typedefstructVnode{

PtrToAdjVNodeFirstEdge;/*边表头指针*/

DataTypeData;/*存顶点的数据*/

/*注意:

很多情况下,顶点无数据,此时Data可以不用出现*/

}AdjList[maxVnum];/*AdjList是邻接表类型*/

(4)邻接表对应图结点的定义

typedefstructGNode*PtrToGNode;

structGNode{

intNv;/*顶点数*/

intNe;/*边数*/

AdjListG;/*邻接表*/

};

typedefPtrToGNodeLGraph;/*以邻接表方式存储的图类型*/

(5)邻接矩阵的定义

typedefstructMNode*PtrToMNode;

structMNode{

intNv;/*顶点数*/

intNe;/*边数*/

WeightTypeG[maxVnum][maxVnum];/*邻接矩阵*/

};

typedefPtrToMNodeMGraph;/*以邻接矩阵存储的图类型*/

(6)BFS存数据的队列

typedefstructQue*Queue;

structQue{

intfront;

intrear;

intdatalist[maxVnum];

};

(7)用于输出最短路径的栈

typedefstructStr*Strack;

structStr{

inttop;

intStrlist[maxVnum];

};

3.重要函数的伪代码

(1)无权图的单源最短路径

voidUnweighted(Vertexs){

Enqueue(s,q);

while(队列不空){

v=Deququ(q);

for(v的每个邻接点w){

if(w没被访问过){

更新w的距离;

path[w]=v;

Enqueue(w,q);

}

}

}

(2)有权图的单源最短路径

voidDijkstra(Vertexs){

while

(1){

v=未收录顶点中的dist最小者;

if(这样的v不存在)

break;

collected[v]=true;

for(v的每个邻接点w)

if(w没被收录){

if(dist[v]+v到w的权值

更新w的最短距离;

path[w]=v;

}

}

}

(3)Depth-firstsearch

访问顶点v;

visited[v]=1;//算法执行前visited[n]=0

w=顶点v的第一个邻接点;

while(w存在){

if(w未被访问)

从顶点w出发递归执行该算法;

w=顶点v的下一个邻接点;}

(4)BFS广度优先搜索

初始化队列Q;visited[n]=0;

访问顶点v;visited[v]=1;顶点v入队列Q;

while(队列Q非空){

v=队列Q的对头元素出队;

w=顶点v的第一个邻接点;

while(w存在){

如果w未访问,则访问顶点w;

visited[w]=1;

顶点w入队列Q;

w=顶点v的下一个邻接点。

}}

4、调试分析

(1)调试过程中遇到的问题是如何解决的。

我是将每一个部分分开设计,运行成功再将他们整合到一起,不免会出现各种各样的问题,单独拿出去就可以运行,但放在一起没有报错,可就是做不对。

而且后来我发现早成这种现象的不是因为程序有大问题,是一些根本就没有注意的小点造成的,例如定义的i加入到程序中就会被其中的i覆盖,结构体定义的不同等等,让我明白以后需要注重整体,在意细节,才能快速的完成任务。

(2)算法的时空分析和改进设想;

首先,利用邻接矩阵一定是稠密图才合算,对DFS时间复杂度为O(n^2),广度优先搜索相同。

而利用邻接表存储稀疏图合算。

对DFS时间复杂度为O(n+e),广度优先搜索相同

Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

Dijkstra:

O(n2)使用与权值为非负的图的单源最短路径。

(2)经验和体会

通过这次设计我得到很深的体会,要好好的利用所学的知识,遇到难题要尽快查阅资料,已得到解决。

 

5、用户使用说明

1.先输入共要创建几个图(多组输入)

2.输入创建图的顶点数

3.输入创建图的边数

4.定义图有无方向(1为有向图,2为无向图)

5.根据边数输入起点、终点、和权值

6.输入DFS与BFS的起点

7.输入两个点求最短路径

 

6、测试结果

建立图:

2

1

4

83

 

1

顶点数:

6

边长:

6

深度搜索起始顶点:

1

结果:

156432

广度搜索起始顶点:

1

结果:

152643

输入1,4,不带权值的最短路径:

154

长度为:

2

输入1,4,不带权值的最短路径:

1234

长度为:

6

开始测试:

 

7、测试情况

测试成功,程序正常进行结果正确。

1.对于第一次循环(无向图):

DFS:

15423

BFS:

152643

不带权的1到4最短路径为:

154

长度为:

2

带权的1到4最短路径为:

1234

长度为:

6

Floyd算法中求最短路径也为6

2.对于第二次循环(有向图):

由于V6与其他顶点反向,所以

DFS:

15432正确

BFS:

15243正确

不带权的1到6最短路径为:

因为1到6逆向

带权的1到4最短路径为:

因为1到6逆向

而在Floyd算法中求1到4最短路径长度还是:

6正确

 

附录(源代码):

#include

#include

#include

#defineINF100

#defineERROR200

#defineflase0

#definetrue1

#definemaxVnum100/*最大顶点数设为100*/

typedefintVertex;/*用顶点下标表示顶点,为整型*//*图的邻接表表示法*/

typedefintWeightType;/*边的权值设为整型*/

typedefcharDataType;/*顶点存储的数据类型设为字符型*/

usingnamespacestd;

intdist[maxVnum];

intpath[maxVnum];

intcollect[maxVnum];

//BFS存数据的队列

typedefstructQue*Queue;

structQue{

intfront;

intrear;

intdatalist[maxVnum];

};

//输出路径的栈

typedefstructStr*Strack;

structStr{

inttop;

intStrlist[maxVnum];

};

/*边的定义*/

typedefstructENode*PtrToENode;

structENode{

VertexV1,V2;/*有向边*/

WeightTypeWeight;/*权重*/

};

typedefPtrToENodeEdge;

/*邻接点的定义*/

typedefstructAdjVNode*PtrToAdjVNode;

stru

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 图表模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1