【发布时间】:2010-03-08 08:10:38
【问题描述】:
为了解决一些问题,我需要计算帕斯卡三角形的变体,其定义如下:
f(1,1) = 1,
f(n,k) = f(n-1,k-1) + f(n-1,k) + 1 for 1 <= k < n,
f(n,0) = 0,
f(n,n) = 2*f(n-1,n-1) + 1.
对于给定的 n,我想有效地获得第 n 行 (f(n,1) .. f(n,n))。另一个限制:如果 f(n,k) >= 2^32,则 f(n,k) 应为 -1。
我的实现:
next :: [Int64] -> [Int64]
next list@(x:_) = x+1 : takeWhile (/= -1) (nextRec list)
nextRec (a:rest@(b:_)) = boundAdd a b : nextRec rest
nextRec [a] = [boundAdd a a]
boundAdd x y
| x < 0 || y < 0 = -1
| x + y + 1 >= limit = -1
| otherwise = (x+y+1)
-- start shoud be [1]
fLine d start = until ((== d) . head) next start
问题:对于非常大的数字,我会遇到堆栈溢出。有没有办法强制haskell评估整个列表?很明显,每行不能包含比上限更多的元素,因为它们最终会变为 -1 并且不会被存储,并且每行仅取决于前一行。由于惰性评估,只有每行的头部被计算,直到最后一行需要它的第二个元素,并且沿途的所有树干都被存储...... 我在 c++ 中有一个非常有效的实现,但我真的想知道是否有办法在 haskell 中完成它。
【问题讨论】:
-
这将有助于提供一个完整的可运行程序。这很接近,但尚不清楚缺少什么或“非常大的数字”是什么意思。
-
我需要接近 2^32 的数字。在 c++ 实现中,算法在线性时间和恒定空间中运行,因为一行最多有 33 个元素(其余为 -1)。
-
您要替换的 C++ 实现是什么?
-
f(n,n) = 2*f(n-1,k-1) + 1。我认为右手边不应该有 k。 -
好吧,我终于得到了一个相当快的 Haskell 版本:pastie.org/864145。然后我将它翻译成 C:pastie.org/864140,C 大约快 10 倍(在我的机器上执行
time triangle 800000 | grep user是 8 毫秒 vs. 100 毫秒。)
标签: algorithm haskell lazy-evaluation pascals-triangle