dijkstra算法针对稠密图和稀疏图的两种不同策略

迪杰斯特拉(dijkstra)算法是一种普遍用于求两点之间(或者说一个给定点到图中其他任意点)的最短路径的算法。但当图的连接较为稠密或者较为稀疏的时候,采用两种不同的思路,可以优化算法的执行速度。

应用于稠密连接图的dijkstra算法

所谓稠密连接就是指图之间的连接路径趋近于n的平方(n为图中节点的个数)。在稠密连接的条件下,dijkstra算法的算法复杂度是O(n^2)。

算法思想是分两步走:

  • 从起点开始,依次找到距离起点最近且没有被遍历过的点。
  • 更新与这个点直接连接的点的最短距离值。

其中,更新最短距离值的状态转移方程为:

其中,x是指当前正在遍历的点,y是指和当前正在遍历的点直接连接的点,map(x,y)是指x和y的距离。

所以很容易得到,第一步的算法复杂度是O(n),第二步也是O(n)。由于两个步骤嵌套执行,所以算法复杂度是O(n^2)。

此算法的伪代码:

1
2
3
for([1:n]):
for([1:n]):找出距离起点最近且没有被遍历过的点
for([1:n]):更新与这个点直接连接的点的最短距离值

应用于稀疏连接图的dijkstra算法

稀疏连接和稠密连接界限的界定没有那么明显,但是在很多问题场景下,节点的数量远远大于与一个节点连接的边的数量。对于这种稀疏连接的图,我们可以将算法复杂度优化到O(mlogn)。其中m为图中边的个数,n为图中节点的个数。

算法思想总体思想和稠密图的类似,但是实现细节上有些不同。

在第一步找距离起点最近且没有被遍历过的点的时候,我们需要用到优先队列,就是在执行第二步更新节点值的时候,将与当前节点直接连接的节点(也就是可能被更新的节点)放入优先队列中,然后在下一步用优先队列直接取出距离最近的节点。我们知道优先队列的增删改查算法复杂度都在O(logn)之内。

在第二步更新当前遍历点直接连接节点的最短距离值的时候,就不用遍历所有节点了。

所以算法思想如下:

  • 从起点开始,依次遍历优先队列中的点。
  • 取与此节点相连接的边,并更新另一头连接节点的距离最小值。
  • 将相连的节点放入优先队列。

此算法的伪代码:

1
2
3
for(q:Queue):优先队列里与原点距离最短的点
for(e:Edge):与此点直接相连的边
将相连的节点放入优先队列;

此算法前两个循环实际上是遍历了m条边,再加上循环内优先队列的开销,可知此算法复杂度都是O(mlogn)。