迪杰斯特拉算法用于解决一个点到另一个点的寻路实现。已知有N个节点,以及节点之间的距离,来求其中一个节点到另一个节点的路径问题。
![eb45c95ef5de9a423f5f50f0a2551a9e.png](https://i-blog.csdnimg.cn/blog_migrate/f8e2632a7eccb563f8276f2123668525.png)
在此算法中,有2个列表,close关闭列表和open开放列表。
close关闭列表:代表已经得到了起点到该列表中所有节点的最短路径
open开放列表:代表访问过,但是还没有加入到close列表中的元素列表集合;
算法流程:
1.将起点Start加入到close关闭列表中,并将起点设置为NewNode节点
2.遍历NewNode能到达的所有节点
a.如果该节点未访问过,将该节点加入到open列表中,更新该点的距离和父节点;
b.如果NewNode到该节点的距离小于老节点到达该节点的距离,更新该节点的距离和父节点;
3.选取open列表中,距离最短的一个点,设置为NewNode。将该节点加入到close列表中,并从open列表中删除
4.重复2-3,直到所有节点都加入到了close列表中。
最终就得到了起点到所有节点的最短路径,如果想打印详细路径,可以从终点根据父节点逆向查找。
详细演示过程:
![1137c44dd269ca6a77d899662c48f652.png](https://i-blog.csdnimg.cn/blog_migrate/50ebce3f5d187f3f1d4abce9ba6ff7b5.png)
根据如图,先构建出一个二维数组的有向图结构
int[,] map = new int[,]
{
{0,6,3,M,M,M},
{M,0,M,5,M,M},
{M,2,0,3,4,M},
{M,M,M,0,2,3},
{M,M,M,M,0,5},
{M,M,M,M,M,0}
};
close 和 open 列表都为空
listClose = new List<Node>();
listOpen = new List<Node>();
![e2c943050269ebf69bfd2b3d09811eef.png](https://i-blog.csdnimg.cn/blog_migrate/c298c27885e7c6729abad568c8ca144e.png)
1.根据有向图得到新节点1能到达的所有节点为 节点2和节点3,遍历该节点所有可达节点:
foreach 节点x in 所有可达节点
{
listOpen.Add(节点x);
if( 起点到新节点的距离 + 新节点到节点x的距离 < 起点到节点x的距离 )
{
起点到节点x的距离 = 起点到新节点的距离 + 新节点到节点x的距离;
节点x 的 父节点 更改为 新节点;
}
}
2.找出open列表中,距离起点最短的节点
遍历open列表,可以找到最短的节点是节点3,
将节点3加入到close列表中,并从open列表中移除
可以将节点3作为新的节点,继续 操作1,直到找到了终点
节点1到节点3最近,将节点3作为新节点继续:
![87c88ceb1384d7f75c4d8cee14856acd.png](https://i-blog.csdnimg.cn/blog_migrate/a16c4f6b97803d504cfc8e8c9b967456.png)
节点3到节点2比节点1到节点2近,所以更新节点2的距离。
且open列表中,起点到节点2最近,将节点2加入close列表中
![d323aa8f8e9b4fa261bb65b276bfb4b6.png](https://i-blog.csdnimg.cn/blog_migrate/8cceeb4c909461053371543f918f5d92.png)
open列表中,起点到节点4最近,将节点4加入close列表中
open列表中,起点到节点5最近,将节点5加入close列表中
![a119f267a28360822220740e005c48fc.png](https://i-blog.csdnimg.cn/blog_migrate/5951df9747cba2ba0c01a66b285b6d09.png)
open列表中,起点到节点6最近,将节点6加入close列表中
![31b4b39423545d8b63fa9e244275f229.png](https://i-blog.csdnimg.cn/blog_migrate/11a4d5a9eaf5ea5eeb108c2fff83d471.png)
遍历结束,可以得到节点1到所有节点的最短距离以及路径
时间复杂度
从复杂度来看,主要是外层循环O(V)与内层循环(枚举v需要O(V),寻找最小的节点需要O(V))产生的,总复杂度为O(V*(V+V)) = O(V^2).
但其实Djikstra算法是可以优化到O(nlogn + m)的级别的 为什么?
因为必须把每个点都标记为已访问(即vis[i] = true),所以外层循环的O(V)时间是无法避免的 但是寻找最小的d[u]的过程可以不必要一个一个重新循环去寻找最小的那个的d[u] 可以通过堆优化来降低复杂度,最简单的做法就是直接用STL中的优先队列priority_queue(STL依赖症(划掉))
代码链接:
文档:迪杰斯特拉算法-代码.note
链接:有道云笔记