【问题标题】:Fastest Dijkstra algorithm for j2MEj2ME 的最快 Dijkstra 算法
【发布时间】:2009-05-10 07:39:10
【问题描述】:

任何人都可以帮助我更快地实现 Dijkstra 算法的 j2ME 吗?我有两个循环,一个在另一个里面。像这样

while(for each item in Q)
{
    //...do something.

    //the following loop is to find the minimum
    for(all un-visited nodes in Q)
    {
       //.. do something to get min.
    }
}

我有将近 23000 个节点和 50000 条连接它们的边......在下面提到的所有改进之后,内部循环平均执行 169330131 次。在我的 w910i 手机上完成这需要 5 分钟,而在我的模拟器上则需要几分钟以上。这对我来说太过分了。有什么改进的建议吗?我已经实施了以下改进。

  1. 使用数组代替向量。
  2. 确保内部循环不考虑访问节点。我所有访问过的节点都在数组的末尾,我节点知道计数。所以,我可以轻松地完全跳过它们。

【问题讨论】:

    标签: java algorithm java-me dijkstra


    【解决方案1】:

    我认为您在问题中的算法是错误的。内循环应该查看外循环中项目的每个未访问的邻居:

    for each (item in Q)
    {
      for each (unvisited neighbour of item)
      {
      }
    }
    

    pseudocode implementation in wikipedia比较:

     1  function Dijkstra(Graph, source):
     2      for each vertex v in Graph:           // Initializations
     3          dist[v] := infinity               // Unknown distance function from source to v
     4          previous[v] := undefined          // Previous node in optimal path from source
     5      dist[source] := 0                     // Distance from source to source
     6      Q := the set of all nodes in Graph
            // All nodes in the graph are unoptimized - thus are in Q
     7      while Q is not empty:                 // The main loop
     8          u := vertex in Q with smallest dist[]
     9          if dist[u] = infinity:
    10              break                         // all remaining vertices are inaccessible
    11          remove u from Q
    12          for each neighbor v of u:         // where v has not yet been removed from Q.
    13              alt := dist[u] + dist_between(u, v) 
    14              if alt < dist[v]:             // Relax (u,v,a)
    15                  dist[v] := alt
    16                  previous[v] := u
    17      return previous[]
    

    【讨论】:

    • 我提到了这个算法。我在其他地方找到了一个更简单的算法。请注意,如果我必须在 Wikipedia 中实现一个,则有两个内部循环。 while Q 不为空://外循环。 u := Q 中具有最小 dist[] 的顶点;// 第一个内循环。 .... 对于 u 的每个邻居 v://第二个内循环。第二个内环较小。它最多可以执行 4-5 次,因为每个节点最多有 5 条边。具有超过 2 条边的节点数量为 23000 个节点中的 1000 个。因此,内部循环的执行时间可以忽略不计。
    • 您是否阅读过维基百科中关于运行时间的部分?它建议使用邻接列表和二进制堆或其他结构作为优先级队列 - 这将在很大程度上消除第一个内部循环
    • 仔细看看,Deekshit - 如果你对 Q 使用优先级队列(堆),找到 Q 中的最小元素是 O(1),这使得总运行时间 O(n+m ) 与节点和边的数量。
    • 感谢 Nick Jonson,我会尝试这种方法。由于目标平台是支持 j2ME 的手机,因此我也有内存消耗的限制。我会试一试的。
    【解决方案2】:

    您的实施有问题。它的复杂度是 O(E + V * log2 (V))。

    这意味着 50000 + 23000 * ~15 = 400 000 次迭代。

    您当前的复杂度几乎是 O(V^2)。

    【讨论】:

      【解决方案3】:

      我提到了这个算法。我在其他地方找到了一个更简单的算法。请注意,如果我必须在 Wikipedia 中实现一个,则有两个内部循环。

      while Q is not empty: //Outer loop. 
        u := vertex in Q with smallest dist[];// First inner loop. 
        .... 
        for each neighbor v of u: //Second inner loop. 
      

      第二个内循环更小。它最多可以执行 4-5 次,因为每个节点最多有 5 条边。具有超过 2 条边的节点数量为 23000 个节点中的 1000 个。因此,内部循环的执行时间可以忽略不计。第一个内循环是问题所在。寻找最小的节点。由于我必须在 j2ME 设备上执行此操作,因此我必须使其占用尽可能少的空间。

      【讨论】:

      • 可以忽略不计吗?您是否对其进行了概要分析并对其进行了测试?上面的伪代码 Dijkstra的算法,所以不是;内循环是必需的。正如 Roman 所说,你的算法几乎是 O(V^2),但是如果你正确地实现算法,没有假设或过早优化,你将得到正确的 O() 复杂度。
      • 是的,我做到了。外循环执行的每次迭代的第一内循环执行的最大次数为 23000(注释数)。但是第二个内循环只执行了 5 次(每个节点的最大边数)。让我们考虑一下我有 25000 个节点的示例。我在第 1000 次迭代中找到了最短路径。因此,第二个内循环对外循环的每次迭代至少执行 24000 次。即 1000*25000。但是第二个内部循环只需要 5 次迭代。即 1000*5(最大)。所以只有瓶颈是第一个内循环。
      • 当我测试第二个循环几乎不消耗 2-3 秒的执行时间。但是第一个循环真的很重。我试图通过节省第二个最小距离将时间减少一半。这减少了 30% 的执行时间。但是增加了代码的复杂度。顺便说一句,该程序在我的台式电脑上花费的时间不超过 2 秒。在我的手机或模拟器上大约需要 5 分钟。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2016-07-30
      • 2021-04-18
      相关资源
      最近更新 更多