heap+dijkstra与SPFA的对比

 

heap+dijkstra与SPFA都是单源最短路的高效算法,到底谁比较快一直各有各的说法。于是心血来潮自己测试了下。

测试工具:cena 0.6

系统: windows vista

CPU: T2130, 1.86Ghz

 

所有程序中,图用相同格式存储,输入,输出,数据都是静态分配

邻接表参考dd的dinic代码

Dijkstra1: 我写的的支持内部修改的heap, 

复杂度O((V+E)logV)

Dijkstra2: STL的priority_queue,更新之后结点直接加进堆中而不是更新堆内的结点

复杂度: ???

Dijkstra3: 朴素的Dijkstra

复杂度O(V^2+E)

SPFA:        经典的bellmen-ford的优化,用的最常见的写法,自己写的queue   

复杂度O(k*E), k接近2

USACO:       usaco中butter一题的标程稍作修改,本质与Dijkstra1相似, 

复杂度O((V+E)logV)

 

TEST 1:2000个点的完全图

 

输入输出用时:2.15-2.9秒, 平均:2.47

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.13  0.10

Dijkstra2: 0.05  0.41

Dijkstra3: 0.21  0.18

SPFA:        1.04  0.97

USACO:       0.29  0.40

 

大规模密集图,大量数据的输入输出占用了大部分时间。单纯计算时间太短难以比较。几种dijkstra都有很好的表现,SPFA由于运行时间对于边数的依赖性,显得逊色不少。

对于Dijkstra1和Dijkstra2 因为是密集图,每次找到一个点后无论是内部更新还是重新插入结点,都要O(log n)的复杂度(虽然插入结点的期望复杂度为O(1),但是由于是重新插入结点,堆内同时存在的总结点数可能会达到E的数量级,增大了常数),工作量都是较大的,堆的优势没有体现出来。 相比之下,朴素的Dijkstra的表现相当不错。

 

TEST 2: 100000个结点的链状图

 

输入输出用时:0.10 - 0.30秒, 平均:0.17

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.03  0.07

Dijkstra2: 0.04  0.07

Dijkstra3: >10   >10

SPFA:        0.03  0.00

USACO:       0.15  0.18

 

对于极端的链状图,SPFA无疑是最合适的了。每个结只进队一次,标准的O(E)。朴素的dijkstra对于这样的图就力不从心了:每次循环都过一遍结点,在松弛,然后发现每次O(V)的时间只松弛了一个点。。

Dijkstra2 由于堆内的结点总数最多有E的数量级,稀疏图里和V接近,劣势没有体现出来。

 

 

TEST 3: 20000个结点的稀疏图(每个点100条边)

 

输入输出用时:2.15-2.40 秒, 平均:2.30

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.33

Dijkstra2: 0.39  0.57

Dijkstra3: 2.20  3.26

SPFA:        5.45  5.11

USACO:       0.27  0.33

 

普通的稀疏图,比TEST 2的密集。 Dijkstra+heap依然是最快的。

比较惊奇的结果是:SPFA居然会比朴素dijkstra还慢……有些出乎预料

原因还没想明白……

 

 

TEST 3: 5000个结点的较密集图(每个点500条边)

 

输入输出用时:2.44-2.99 秒, 平均:2.75

 

用时(除去平均输入输出时间)

单位:秒:

Dijkstra1: 0.30  0.32

Dijkstra2: 0.39  0.33

Dijkstra3: 0.40  0.40

SPFA:        1.04  1.04

USACO:       0.40  0.19

 

比较密集的图。SPFA的表现仍然不佳,Dijkstra+heap 任然是王道,朴素dijkstra的劣势逐渐缩小

 

总结:

 

Dijkstra1对于各种图都有良好表现,但是编程复杂度较高,需要准备模板。Dijkstra2速度也很不错,普遍略逊于Dijkstra1。Dijkstra3对于密集图有不错的表现。

SPFA表现不尽如人意。但是由于SPFA编程复杂度低,适用于各种图,也可以用来负权环,适合比赛使用。

 

编程复杂度:SPFA>naive dijkstra>STLheap+dijkstra>heap+dijkstra(越靠前越容易是写)

综合效率:   heap+dijkstra>STLheap+dijkstra> SPFA>naive dijkstra

比赛的时候 STLheap+dijkstra 和 SPFA 是不错的选择

 

dijkstra1:

 

 

dijkstra2:

 

 

dijkstra3:

 

 

SPFA:

 

USACO:

 

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
java.lang.OutOfMemoryError: Java heap space是Java程序在运行过程中遇到的一种内存溢出错误。它表示Java堆内存不足以容纳程序所需的对象。当程序需要创建新的对象时,但是堆内存已经被占满时,就会抛出这个错误。 解决这个问题的方法有以下几种: 1. 增加堆内存大小:可以通过修改JVM的启动参数来增加堆内存的大小。可以使用-Xmx参数来指定最大堆内存大小,例如-Xmx2g表示将最大堆内存设置为2GB。 2. 优化程序内存使用:可以通过检查程序中是否存在内存泄漏或者不必要的对象引用来优化内存使用。确保及时释放不再使用的对象,避免创建过多的临时对象。 3. 使用更高效的数据结构:如果程序中使用了大量的数据结构,可以考虑使用更高效的数据结构来减少内存占用。例如,使用HashMap代替ArrayList可以减少内存占用。 4. 分析内存使用情况:可以使用工具来分析程序的内存使用情况,找出内存占用较大的对象或者代码段,并进行优化。常用的工具有jvisualvm、jprofiler等。 5. 调整垃圾回收策略:可以通过调整垃圾回收策略来减少内存占用。可以使用不同的垃圾回收器,调整垃圾回收的参数等。 下面是一个示例代码,演示如何增加堆内存大小来解决java.lang.OutOfMemoryError: Java heap space错误: ```java public class HeapSpaceDemo { public static void main(String[] args) { // 创建一个大对象,占用大量内存 byte[] bigObject = new byte[1024 * 1024 * 1024]; // 打印对象的大小 System.out.println("Object size: " + bigObject.length); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值