直接 Dijkstra 算法的时间复杂度
Posted
技术标签:
【中文标题】直接 Dijkstra 算法的时间复杂度【英文标题】:Time Complexity of Straight Forward Dijkstra's Algorithm 【发布时间】:2020-04-15 03:27:05 【问题描述】:我很难看到直接实现 Dijkstra 算法(没有堆)的 O(mn) 界限。在我的实现和其他实现中,我发现主循环迭代 n-1 次(对于不是源的每个顶点,n-1),然后在每次迭代中找到最小顶点是 O(n)(检查队列中的每个顶点并找到到源的最小距离),然后每个发现的最小顶点最多有 n-1 个邻居,因此更新所有邻居是 O(n)。在我看来,这会导致 O(n^2) 的界限。下面提供了我的实现
public int[] dijkstra(int s)
int[] dist = new int[vNum];
LinkedList queue = new LinkedList<Integer>();
for (int i = 0; i < vNum; i++)
queue.add(i); // add all vertices to the queue
dist[i] = Integer.MAX_VALUE; // set all initial shortest paths to max INT value
dist[s] = 0; // the source is 0 away from itself
while (!queue.isEmpty()) // iterates over n - 1 vertices, O(n)
int minV = getMinDist(queue, dist); // get vertex with minimum distance from source, O(n)
queue.remove(Integer.valueOf(minV)); // remove Integer object, not position at integer
for (int neighbor : adjList[minV]) // O(n), max n edges
int shortestPath = dist[minV] + edgeLenghts[minV][neighbor];
if (shortestPath < dist[neighbor])
dist[neighbor] = shortestPath; // a new shortest path have been found
return dist;
我不认为这是正确的,但我很难看到 m 因素在哪里。
【问题讨论】:
【参考方案1】:您的实现确实消除了 M 因素,至少如果我们只考虑简单的图(两个顶点之间没有多重边)。是 O(N^2)!如果您遍历所有可能的边而不是顶点,复杂度将为 O(N*M)。
编辑:嗯,更具体地说,实际上是 O(M + N^2)。在您的算法中更改某些顶点中的值需要 O(1) 时间,并且每次考虑边时都可能发生,换句话说,M 次。这就是复杂性中有 M 的原因。
不幸的是,如果你想使用简单的堆,复杂度将是 O(M* log M)(或 M log N)。为什么?您无法快速更改堆中的值。因此,如果 dist[v] 突然减小,因为您找到了一条新的、更好的通往 v 的路径,您不能只在堆中更改它,因为您并不真正知道它的位置。您可以将 v 的副本放入堆中,但堆的大小将是 O(M)。即使您存储位置并巧妙地更新它,堆中可能有 O(N) 项,但您仍然必须在每次更改后更新堆,这需要 O(堆大小)。您最多可以将值更改为 O(M) 次,这会给您带来 O(M* log M (or N)) 复杂度
【讨论】:
以上是关于直接 Dijkstra 算法的时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章