【发布时间】:2021-02-20 11:18:07
【问题描述】:
前段时间我需要使用算法来解决一个 KP 问题,在 haskell 中
这是我的代码的样子:
stepKP :: [Int] -> (Int, Int) -> [Int]
stepKP l (p, v) = take p l ++ zipWith bestOption l (drop p l)
where bestOption a = max (a+v)
kp :: [(Int, Int)] -> Int -> Int
kp l pMax = last $ foldl stepKP [0 | i <- [0..pMax]] l
main = print $ kp (zip weights values) 20000
where weights = [0..2000]
values = reverse [8000..10000]
但是当我尝试执行它时(在使用 ghc 编译后,没有标志),它似乎很糟糕:
这是命令./kp -RTS -s的结果
1980100
9,461,474,416 bytes allocated in the heap
6,103,730,184 bytes copied during GC
1,190,494,880 bytes maximum residency (18 sample(s))
5,098,848 bytes maximum slop
2624 MiB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 6473 colls, 0 par 2.173s 2.176s 0.0003s 0.0010s
Gen 1 18 colls, 0 par 4.185s 4.188s 0.2327s 1.4993s
INIT time 0.000s ( 0.000s elapsed)
MUT time 3.320s ( 3.322s elapsed)
GC time 6.358s ( 6.365s elapsed)
EXIT time 0.000s ( 0.000s elapsed)
Total time 9.679s ( 9.687s elapsed)
%GC time 0.0% (0.0% elapsed)
Alloc rate 2,849,443,762 bytes per MUT second
Productivity 34.3% of total user, 34.3% of total elapsed
我认为我的程序占用 O(n*w) 内存,而它可以在 O(w) 中完成。 (w为总容量)
这是懒惰评估占用太多空间的问题,还是其他问题? 这段代码如何更节省内存和时间?
【问题讨论】:
-
foldl->foldl'? -
我确实试过了,但这没什么区别......
-
另一个快速尝试的方法是在启用优化的情况下进行编译。
-
@rambi 我会使用
[10000,9999..8000]而不是reverse [8000..10000]。 stackoverflow.com/a/6806519/1364288 反向总是需要物化整个列表。另外splitAt会比单独使用take和drop更好hackage.haskell.org/package/base-4.14.1.0/docs/… -
嗯,更糟糕的是!
标签: haskell memory lazy-evaluation space-complexity