直进Dijkstra算法的时间复杂度

斯宾塞

我很难看到直接实现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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章