NJUPT南京邮电大学数据结构实验三(图的基本运算及智能交通中的最佳路径选择问题)

仅提供思路,请勿照抄 !!!

一、实验目的和要求
实验目的:
1、掌握在图的邻接矩阵和邻接表存储结构实现图的基本运算的算法。
2、学习使用图算法解决应用问题的方法。
实验内容:

  1. 图的基本运算。
    (1)验证教材中关于在邻接矩阵和邻接表两种不同存储结构上实现图的基本运算的算法。
    (2)在邻接矩阵和邻接表存储结构上实现图的深度和宽度优先遍历算法。
    (3)设计主函数,测试上述运算。
  2. 飞机最少换乘次数问题。
    (1)设有n个城市,编号为0~n-1,m条航线的起点和终点由用户输入提供。寻找一条换乘次数最少的线路方案。
    (2)参考:可以使用有向图表示城市间的航线;只要两城市间有航班,则图中这两点间存在一条权值为1的边;可以使用Dijkstra算法实现。

二、实验原理及内容
1、算法设计
(1)算法整体思路—函数调用关系

(2)DFS深度遍历

(3)BFS宽度遍历

(4)迪杰斯特拉算法

2、算法实现与分析

算法的详细分析及时间复杂度的分析(其中n为顶点数 e为边数)

代码参考书上相关代码
①邻接矩阵存储的图的基本运算和遍历算法
邻接矩阵初始化MInit——时间复杂度O(n^2)
邻接矩阵的撤销MDestroy——时间复杂度O(n)
边的搜索MExist——时间复杂度O(1)
边的插入MInser——时间复杂度O(1)
边的删除MRemove——时间复杂度O(n)
图的深度优先遍历MDFSGragh——时间复杂度O(n^2)
图的宽度优先遍历MBFSGragh——时间复杂度O(n^2)
②邻接表存储的图的基本运算和遍历算法
邻接表初始化LInit——时间复杂度O(n)
邻接表的撤销LDestroy——时间复杂度O(n+e)
边的搜索LExist——最坏时间复杂度O(e)
边的插入LInsert——时间复杂度O(1)
边的删除LRemove——最坏时间复杂度O(e)
图的深度优先遍历LDFSGragh——时间复杂度O(n+e)
图的宽度优先遍历LBFSGragh——时间复杂度O(n+e)
③飞机最少换乘次数问题
邻接矩阵初始化Minit——时间复杂度O(n^2)
边的插入MInsert——时间复杂度O(e)
迪杰斯特拉算法求最少换乘次数Dijkstra——时间复杂度O(n^2)

3、实验结果与结论
(1)测试数据及运行结果
邻接矩阵存储的图的基本运算和遍历算法测试

邻接表存储的图的基本运算和遍历算法测试

从这个例子可以看出来,两种存储方式下BFS和DFS输出的结果可能不同
原因实际上是这两种BFS、DFS的结果都是对的,只不过邻接表存储的图存储时会把后输入的存到最前面。

像这样交换一下第2条边和第3条边的顺序,输出结果就和邻接矩阵一样了

从这个例子可以看出来,BFS和DFS的结果可能是不同的
还有在这个例子里当输入重复时会提示该边重复

当输入无效时会提示输入无效
飞机最少换乘次数问题算法测试


当有两条同样少换乘次数的路线时,会优先输出字典序更小的一条

这一例子同样印证了上面的结论
(2)实验结论
存储图时可以使用邻接矩阵和邻接表两种方式存储,邻接矩阵的存储结果不受输入顺序影响,而邻接表中后插入的边会存到最前面。在图的遍历DFS和BFS中,邻接表存储的时间复杂度更低,邻接矩阵存储的时间复杂度更高。在迪杰斯特拉算法求最短路径的结果中,在路径长度相等的情况下,会优先输出字典序更小的路径,这是由于遍历邻接矩阵过程中是按顺序遍历的。

三、实验小结(包括问题和解决方法、心得体会、意见与建议等)
(一)实验中遇到的主要问题及解决方法
在求最少换乘次数的过程中,原本我是在plane函数里定义d和path数组,调用dijkstra算法之后,在plane函数里输出d[u](u为终点序号),但是我发现这样无法输出正确答案,后来发现原因是,dijkstra算法只是在函数内部更新了d和path数组,并没有改变plane函数里的d和path数组的值。于是我将终点u也传参到dijkstra函数里,并且将dijkstra函数的返回值设定为最少换乘次数,这样就可以得出正确答案了。
还有我一开始在plane函数里调用Minit函数时误把初始化没有边时的取值 noEdgeValue写成0,这样会导致输出结果一直错误,应改为INFTY,即 初始化没有边时的取值为最大值。
输出换乘的方案,我原本是直接while(path[u]!=-1)时输出path[u],然后u=path[u];继续循环,后来我发现这样输出的是反的方案,于是我想到可以利用堆栈,把序号入栈,然后最后弹栈,但是c语言没有堆栈的STL,为了方便,我最后使用了数组来存储序号,并且最终倒序输出数组。
在测试邻接矩阵和邻接表存储的图的算法的主函数里的输入中,我原本采用的是使用do-while一直循环输入,直到用户输入特定字符结束,但是我后来改成了,一开始读取图的边数m再输入的方式,其实这两种方法都可以,但是第二种方法可以在一开始就更好地判定输入的边数是否合理。

可改进之处:我的代码中没有加上无向图或有向图的选项,只有有向图,其实无向图只需要把输入的起点和终点交换位置再插入一次即可。
(二)实验心得
通过这次的实验,我学习到了图存储的两种方式——邻接矩阵和邻接表,还有深度优先遍历DFS和宽度优先遍历BFS的区别,还有Dijkstra算法求最短路的方法。求最短路也可以利用Floyd算法,但是在已知起点的情况下,使用Dijkstra算法的时间复杂度会更低,而Floyd算法可以在之后处理后多次输入起点和终点来求最短路。还有这次实验也让我复习了队列和堆栈的相关知识。
(三)意见与建议
或许可以在解决飞机最少换乘次数问题中加入删除操作的相关问题背景,包括边的删除和点的删除(点的删除实质上是删除该边相连的所有边)。比如某一条航线故障突然取消,或者某一个机场突然下大暴雨无法进行飞机升降,然后再去求最少的换乘次数。

posted @ 2025-02-20 15:00  jxt0823  阅读(102)  评论(0)    收藏  举报