图的最短路径算法汇总
这种题目在图里面也不算非常常见 但是一旦见到 这算法就很明显 所以看到这种题目就应该立刻想到最短路径算法 然后需要立刻定位到自己需要用的那种算法。不然虽然知道最短路径算法 但是不知道要选择哪个 就会十分慌乱 心态立刻就崩了。所以本文就回顾一下有哪些图的最短路径算法,这些算法的应用场景有哪些?我们经常遇见的问题有哪些种类?
经常遇见的问题总类:
确定起点 求最短路径
确定终点 求最短路径(跟确定起点的没有区别)
确定起点终点的最短路径
全局最短路径(即找到所有两点之间的最短路径 可以想象的到 最后要返回一个二维矩阵,matrix[i][j] represents for the shortest distance between the node i and the node j)
我们已知的图的算法有哪些?
dijkstra算法:能够解决单源最短路径 即从某个固定的起点出发 到每个节点的最短路径。此种算法基于BFS,适用于(有向图无向图)(正权重)的图
bellman-ford算法:能够解决单源最短路径问题,同样基于BFS 适用于(有向图无向图)(正权重负权重)而且能够解决存在负环的问题(因为负环一直走下去永远最小)
floyd-warshall算法:用来解决全局最短路径问题 最大的特点就是他的三个for 这个代码也是非常简单的,而且也能解决有负权边的问题
所以综上所述 不能够解决负权环问题的只有Dijkstra算法。
下面详细的来说一下这三个算法:
dijkstra算法:
假设我们用邻接表来表示顶点之间的关系(有权重或者无权重)然后要用一个数组dis表示起始地点到其他各个顶点的距离,这个是我们要维护和最后输出的,初始化为正无穷。
用通俗的话来说这个算法 就是从起点开始 在起点向外扩的边中 寻找最短的路径 就把那个节点也一并拉过来 然后看看这两个节点组成的图 与外界链接的所有的边中 最短的是哪个,然后再把那个节点拉过来。就这样一直拉一直拉 直到所有的节点都被拉过来。说白了 就是一个从一个节点出发 不断扩张的过程。
bellman-ford: (没搞太明白)
Bellman-ford 算法比dijkstra算法更具普遍性,因为它对边没有要求,可以处理负权边与负权回路。缺点是时间复杂度过高,高达O(VE), V为顶点数,E为边数。
for (var i = 0; i < n - 1; i++) {
for (var j = 0; j < m; j++) {//对m条边进行循环
var edge = edges[j];
// 松弛操作
if (distance[edge.to] > distance[edge.from] + edge.weight ){
distance[edge.to] = distance[edge.from] + edge.weight;
}
}
}
floyd-warshall算法:
基本思想特别简单 就是我们想找从i到j的最短路径 那么任意节点都可以作为中间节点,就算是i或者j节点也可以。
而整个算法所基于的公式,就是下面这个(i到j的最短路径两种可能 要么经过k 要么不经过k)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
但是我们要注意,这里的循环是kij而不是ijk,具体为什么参见本博主其他文章。
不要忘了bellman-ford这个算法,前半部分Richard Bellman是动态规划的提出者。