我很难看到直接实现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个因素在哪里。
至少在我们仅考虑简单图形(两个顶点之间没有多个边)的情况下,您的实现确实消除了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(或N))复杂
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句