全双路最短路径问题的最快实现?

Eug*_*nio 7 c algorithm implementation dijkstra shortest-path

我有一个加权图表30k节点160k边,没有负权重.我想计算从所有节点到其他节点的所有最短路径.我想我不能假设任何特定的启发式来简化问题.

我尝试使用这个Dijkstra C实现http://compprog.wordpress.com/2007/12/01/one-source-shortest-path-dijkstras-algorithm/,这是针对单个最短路径问题,调用函数dijkstras ()我所有的30个节点.你可以想象,这需要很长时间.目前我没有时间自己编写和调试代码,我必须尽快计算这些路径并将它们存储在数据库中,这样我就可以找到另一个更快的解决方案了,你有没有有小费吗?

我必须在最近的8GB内存的macbook pro上运行它,我想找到一个不超过24小时完成计算的解决方案.

非常感谢提前!!

欧亨尼奥

tem*_*def 13

我查看了您在评论中发布的Dijkstra算法链接,我相信这是您效率低下的根源.在内部Dijkstra循环内部,它使用一种极其未经优化的方法来确定下一个要探索的节点(每个步骤对每个节点进行线性扫描).有问题的代码分为两个部分.第一个是此代码,它试图找到要操作的下一个节点:

mini = -1;
for (i = 1; i <= n; ++i)
    if (!visited[i] && ((mini == -1) || (d[i] < d[mini])))
         mini = i;
Run Code Online (Sandbox Code Playgroud)

因为此代码嵌套在访问每个节点的循环内,所以复杂性(如链接中所述)为O(| V | 2),其中| V | 是节点数.在你的情况下,因为| V | 是30,000,整个循环将有9亿次迭代.这是非常缓慢的(正如你所见),但没有理由必须做这么多工作.

这里有另一个麻烦点,它试图找出图中哪个边缘应该用于降低其他节点的成本:

for (i = 1; i <= n; ++i)
   if (dist[mini][i])
       if (d[mini] + dist[mini][i] < d[i])
           d[i] = d[mini] + dist[mini][i];
Run Code Online (Sandbox Code Playgroud)

这将扫描邻接矩阵中的整行,寻找要考虑的节点,这需要时间O(n),而不管有多少外出边缘离开节点.

虽然您可以尝试将此版本的Dijkstra修复为更优化的实现,但我认为这里的正确选择只是抛弃此代码并找到更好的Dijkstra算法实现.例如,如果您使用来自使用二进制堆实现的Wikipedia文章中的伪代码,则可以在O(| E | log | V |)中运行Dijkstra算法.在您的情况下,这个值刚刚超过200万,比您当前的方法快约450倍.这是一个巨大的差异,我愿意打赌,通过更好的Dijkstra实现,你最终会在比以前更短的时间内完成代码.

最重要的是,您可能需要考虑并行运行所有Dijkstra搜索,正如Jacob Eggers指出的那样.此凸轮可为您提供每个处理器的额外速度提升.结合上述(并且更为关键)修复,这可能会给您带来巨大的性能提升.

如果您打算在更密集的数据集(边数接近| V | 2/log | V |)上运行此算法,那么您可能需要考虑切换到Floyd-Warshall算法.每个节点运行一次Dijkstra算法(有时称为Johnson算法)需要时间O(| V || E | log | V |)时间,而使用Floyd-Warshall需要O(| V | 3)时间.但是,对于您提到的数据集,图表非常稀疏,因此运行多个Dijkstra实例应该没问题.

希望这可以帮助!

  • @ Eugenio-正如我在回答中所提到的,我强烈建议不要在这里使用Floyd-Warshall,因为它的效率远低于反复调用Dijkstra的算法.如果你时间紧迫,你可能最好花几个小时寻找/编写一个好的Dijkstra算法并且只使用它,因为你减少执行时间的时间将使得有可能获得结果,而不是使用一个慢的版本,不会给你任何东西. (2认同)

Rob*_*aus 2

你的图有什么特殊的结构吗?该图是平面的(或接近平面的)吗?

我建议不要尝试存储所有最短路径,相当密集的编码(30k^2“下一步去哪里”条目)将占用 7 GB 内存。

有什么应用?当您需要找到特定的最短路径时,您确定执行双向 Dijkstra(或 A*,如果您有启发式)不够快吗?