最短路径算法gydF4y2Ba
最短路径算法是为解决最短路径问题而设计的一组算法。最短路径问题大多数人都有一些直觉上的熟悉:给定两点A和B,它们之间的最短路径是什么?然而,在计算机科学中,最短路径问题可以有不同的形式,因此需要不同的算法来解决所有的问题。gydF4y2Ba
为了简单和通用性,最短路径算法通常在一些输入图上操作,gydF4y2Ba .这个图是由一组顶点组成的,gydF4y2Ba 边,gydF4y2Ba ,连接它们。如果边具有权值,则该图称为加权图。有时这些边是双向的,这个图称为无向图。有时图中甚至会有循环。这些细微的差别使得一种算法比另一种算法更适合于特定的图类型。下图是一个图表示例。gydF4y2Ba
也有不同类型的最短路径算法。也许你需要找到A点到B点之间的最短路径,但也许你需要找到A点到图中所有其他点之间的最短路径。gydF4y2Ba
最短路径算法有许多应用。如前所述,像谷歌或Apple maps这样的地图软件使用最短路径算法。它们对路网、运营和物流研究也很重要。最短路径算法对于计算机网络也非常重要,比如互联网。gydF4y2Ba
任何帮助你选择路线的软件都使用某种形式的最短路径算法。例如,谷歌Maps让您输入一个起点和一个终点,它将为您解决最短路径问题。gydF4y2Ba
类型的图表gydF4y2Ba
图有许多变体。第一个性质是它的边的方向性。边可以是单向的,也可以是双向的。如果它们是单向的,这个图叫做agydF4y2Ba导演gydF4y2Ba图。如果它们是双向的(意思是它们是双向的),这个图被称为agydF4y2Ba无向gydF4y2Ba图。在一些边是有向的而另一些边不是的情况下,双向边应该被交换为实现相同功能的2条有向边。这个图现在是完全有向的。gydF4y2Ba
图的第二个性质与边的权重有关。边可以没有权值,在这种情况下,图被称为gydF4y2Ba未加权的gydF4y2Ba.如果边有权值,这个图就被称为gydF4y2Ba加权gydF4y2Ba.这里有一个额外的警告:图可以允许有负权边。负权边的包含禁止使用一些最短路径算法。gydF4y2Ba
图的第三个影响算法使用的特性是循环的存在。循环被定义为任意路径gydF4y2Ba 通过一个图,gydF4y2Ba ,它访问同一个顶点,gydF4y2Ba 不止一次。所以,如果一个图有任意一条路径其中包含一个循环,这个图就被称为gydF4y2Ba循环gydF4y2Ba.gydF4y2Ba无环gydF4y2Ba图,没有循环的图,允许在算法的使用上有更多的自由。gydF4y2Ba
最短路径算法的类型gydF4y2Ba
有两种主要的最短路径算法,单源和全对。这两种类型的算法都以自己的方式表现得最好。由于增加了复杂性,所有对算法的运行时间更长。所有最短路径算法都返回可用于查找最短路径的值,即使这些返回值在gydF4y2Ba类型gydF4y2Ba或者从一个算法到另一个算法。gydF4y2Ba
单一gydF4y2Ba
单源最短路径算法的工作原理如下:gydF4y2Ba
给定一个图gydF4y2Ba 顶点,gydF4y2Ba ,边gydF4y2Ba 与权函数gydF4y2Ba ,和单个源顶点,gydF4y2Ba ,返回的最短路径gydF4y2Ba 的所有其他顶点gydF4y2Ba .gydF4y2Ba
如果算法的目标是寻找两个给定顶点之间的最短路径,gydF4y2Ba 而且gydF4y2Ba ,那么当找到最短路径时,算法就可以简单地停止。因为没有办法决定要先“完成”哪个顶点,所有求解两个给定顶点之间最短路径的算法都有相同的最差情况gydF4y2Ba渐近的复杂性gydF4y2Ba作为单源最短路径算法。gydF4y2Ba
这个范例也适用于gydF4y2Basingle-destination最短路径gydF4y2Ba问题。通过反转图中的所有边,单目的地问题可以简化为单源问题。给定一个目标顶点,gydF4y2Ba ,该算法将找到最短路径gydF4y2Ba开始gydF4y2Ba在所有其他顶点和结束点处gydF4y2Ba .gydF4y2Ba
全对gydF4y2Ba
全对最短路径算法遵循以下定义:gydF4y2Ba
给定一个图gydF4y2Ba 顶点,gydF4y2Ba ,边gydF4y2Ba 与权函数gydF4y2Ba 返回的最短路径gydF4y2Ba 来gydF4y2Ba 对所有gydF4y2Ba 在gydF4y2Ba .gydF4y2Ba
全对问题最常见的算法是gydF4y2Bafloyd-warshall算法gydF4y2Ba.该算法返回一个值的矩阵gydF4y2Ba ,其中每个单元格gydF4y2Ba 最短路径到顶点的距离是多少gydF4y2Ba 到顶点gydF4y2Ba .路径重构可以找到实现最短路径的实际路径,但它不是基本算法的一部分。gydF4y2Ba
算法gydF4y2Ba
Bellman-Ford算法解决了一般情况下的单源问题,其中边可以具有负权,图是有向的。如果图形是无向的,它将不得不修改,在每个方向上包括两条边,使其有向。gydF4y2Ba
Bellman-Ford有一个特性,它可以检测到从源可达的负权环,这意味着不存在最短路径。如果存在一个负权环,一条路径可以在这个环上无限运行,将路径成本降低到gydF4y2Ba .gydF4y2Ba
如果没有负权循环,那么Bellman-Ford将返回最短路径的权值连同路径本身。gydF4y2Ba
Dijkstra算法利用gydF4y2Ba广度优先搜索gydF4y2Ba(这不是单源最短路径算法)来解决单源问题。它确实对图施加了一个约束:不能有负权边。然而,对于这一约束,Dijkstra大大改进了Bellman-Ford的运行时。gydF4y2Ba
Dijkstra的算法有时也用于解决全对最短路径问题,只需在所有的顶点上运行它gydF4y2Ba .同样,这要求所有边的权值都是正的。gydF4y2Ba
拓扑排序gydF4y2Ba
对于有向无环图(DAGs),出现了一个非常有用的工具来寻找最短路径。通过执行gydF4y2Ba拓扑排序gydF4y2Ba在图中的顶点上,最短路径问题在线性时间内是可解的。gydF4y2Ba
拓扑排序是对所有顶点进行排序,这样对于每条边gydF4y2Ba 在gydF4y2Ba ,gydF4y2Ba 之前gydF4y2Ba 在订购。在DAG中,最短路径总是定义得很好,因为即使有负权边,也不可能有负权环。gydF4y2Ba
Floyd-Warshall算法解决了全对最短路径问题。它使用一个gydF4y2Ba动态规划gydF4y2Ba这样做的方法。Floyd-Warshall可能存在负边权值。gydF4y2Ba
Floyd-Warshall利用了以下观察结果:从A到C的最短路径要么是A到B的最短路径加上B到C的最短路径gydF4y2Ba或gydF4y2Ba它是从A到C的最短路径已经被找到了。这可能看起来微不足道,但正是它使Floyd-Warshall可以用经典的动态规划方法从更小的最短路径构建最短路径。gydF4y2Ba
Floyd-Warshall算法对稠密图(意味着有很多边)工作得很好,而Johnson算法对稀疏图(意味着只有很少的边)工作得最好。在稀疏图中,与Floyd-Warshall算法相比,Johnson算法具有较低的渐近运行时间。gydF4y2Ba
Johnson算法利用了重权的概念,它在多个顶点上使用Dijkstra算法,一旦完成对边缘的重权,就可以找到最短路径。gydF4y2Ba
比较的算法gydF4y2Ba
下面列出了最短路径算法的运行时。gydF4y2Ba
参见:gydF4y2Ba大O符号gydF4y2Ba.gydF4y2Ba
算法gydF4y2Ba | 运行时gydF4y2Ba |
bellmangydF4y2Ba | |
迪杰斯特拉(列表)gydF4y2Ba | |
拓扑排序gydF4y2Ba | |
Floyd-WarshallgydF4y2Ba | |
约翰逊的gydF4y2Ba | *gydF4y2Ba |
*此运行时假设实现使用gydF4y2Ba斐波那契堆gydF4y2Ba.gydF4y2Ba
通常情况下,使用哪种算法的问题并不取决于个人;它仅仅是一个函数,关于被操作的图和被解决的最短路径问题。gydF4y2Ba
对于具有负权边的图,单源最短路径问题需要Bellman-Ford算法才能成功。对于密集图和全对问题,应该使用Floyd-Warshall。gydF4y2Ba
然而,有一些微妙的区别。对于稀疏图和全对问题,使用Johnson的算法可能是显而易见的。然而,如果没有负边权值,那么实际上使用Dijkstra的算法更好gydF4y2Ba二进制堆gydF4y2Ba在实现。从每个顶点运行Dijsktra将产生更好的结果。gydF4y2Ba
从空间复杂度的角度来看,许多算法是相同的。例如,在它们最基本的形式中,Bellman-Ford和Dijkstra是完全相同的,因为它们使用相同的图表示。然而,当使用先进的数据结构(如斐波那契或二进制堆)加速这些算法时,执行算法所需的空间就会增加。就像算法中常见的那样,空间常常被用来换取速度。gydF4y2Ba
改进gydF4y2Ba
随着时间的推移,这些算法得到了改进。例如,Dijkstra的算法最初是使用列表实现的,运行时为gydF4y2Ba .但是,当使用二进制堆时,运行时为gydF4y2Ba 已经实现了。当使用fibonacci堆时,可以实现一种实现gydF4y2Ba 而另一个人可以做到gydF4y2Ba 在哪里gydF4y2Ba 是边权的有界常数。gydF4y2Ba
Bellman-Ford算法已在gydF4y2Ba .如果在正确类型的图(稀疏图)上使用该实现是有效的。gydF4y2Ba