《挑战程序设计竞赛》里面介绍了三种方法: Bellman-Ford、Dijkstra and Floyd算法
三者区别也都很明显:优化
Bellman-Ford:spa
求单源最短路,能够判断有无负权回路(如有,则不存在最短路), 时效性较好,时间复杂度O(VE)。设计
Bellman-Ford算法是求解单源最短路径问题的一种算法。队列
单源点的最短路径问题是指: 给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。it
与Dijkstra算法不一样的是,在Bellman-Ford算法中,边的权值能够为负数。 设想从咱们能够从图中找到一个环路(即从v出发,通过若干个点以后又回到v)且这个环路中全部边的权值之和为负。那么经过这个环路,环路中任意两点的最短路径就能够无穷小下去。若是不处理这个负环路,程序就会永远运行下去。 而Bellman-Ford算法具备分辨这种负环路的能力。ast
Dijkstra:程序设计
求单源、无负权的最短路。时效性较好,时间复杂度为O(V*V+E)。 源点可达的话,O(V*lgV+E*lgV)=>O(E*lgV)。 当是稀疏图的状况时,此时E=V*V/lgV,因此算法的时间复杂度可为O(V^2) 。如果斐波那契堆做优先队列的话,算法时间复杂度,则为O(V*lgV + E)。 test
Floyd:效率
求多源、无负权边的最短路。用矩阵记录图。时效性较差,时间复杂度O(V^3)。 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,能够正确处理有向图或负权的最短路径问题。
Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2)。
Floyd-Warshall的原理是动态规划: 设Di,j,k为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度。 若最短路径通过点k,则Di,j,k = Di,k,k-1 + Dk,j,k-1; 若最短路径不通过点k,则Di,j,k = Di,j,k-1。 所以,Di,j,k = min(Di,k,k-1 + Dk,j,k-1 , Di,j,k-1)。
在实际算法中,为了节约空间,能够直接在原来空间上进行迭代,这样空间可降至二维。 Floyd-Warshall算法的描述以下: for k ← 1 to n do for i ← 1 to n do for j ← 1 to n do if (Di,k + Dk,j < Di,j) then Di,j ← Di,k + Dk,j; 其中Di,j表示由点i到点j的代价,当Di,j为 ∞ 表示两点之间没有任何链接。
后来,我看Bellman-Ford的队列优化,SPFA(Shortest Path Faster Algorithm )。
SPFA:
是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。(k<<V)。
与Bellman-ford算法相似,SPFA算法采用一系列的松弛操做以获得从某一个节点出发到达图中其它全部节点的最短路径。所不一样的是,SPFA算法经过维护一个队列,使得一个节点的当前最短路径被更新以后没有必要马上去更新其余的节点,从而大大减小了重复的操做次数。
SPFA算法能够用于存在负数边权的图,这与dijkstra算法是不一样的。
与Dijkstra算法与Bellman-ford算法都不一样,SPFA的算法时间效率是不稳定的,即它对于不一样的图所须要的时间有很大的差异。
在最好情形下,每个节点都只入队一次,则算法实际上变为广度优先遍历,其时间复杂度仅为O(E)。另外一方面,存在这样的例子,使得每个节点都被入队(V-1)次,此时算法退化为Bellman-ford算法,其时间复杂度为O(VE)。
SPFA算法在负边权图上能够彻底取代Bellman-ford算法,另外在稀疏图中也表现良好。可是在非负边权图中,为了不最坏状况的出现,一般使用效率更加稳定的Dijkstra算法,以及它的使用堆优化的版本。一般的SPFA算法在一类网格图中的表现不尽如人意。