我想出了以下有效的尾递归斐波那契生成器:

let {
  fibo :: Integral x => [x]->x->x->x->[x]
  fibo l x y 0 = l
  fibo l x y n = fibo (l ++ [y+x] ++ [y+x+y]) (x+y) (y+x+y) (n-1)
}

请原谅我将整个实现放在一行中,因为我正在使用 GHCi 并且还没有完全学会如何将它放在一个文件中并运行(我还没有到达那里)。我想知道的是这个电话是如何调用的:
fibo [0, 1] 0 1 5

可以改进。我不想用 0 和 1 传递初始列表,然后再用限制传递 0 和 1。我相信实现是可以改变的。可以做哪些改变?

最佳答案

您的算法是尾递归的,但看起来它还有其他缺点,即 1)您正在通过附加到结果列表的末尾来构建结果列表,以及 2)它不是懒惰的。

对于 1),请注意,当您附加两个列表 a ++ b 时,您基本上必须重新分配 a 。在您的情况下,a 是不断增长的斐波那契数列,b 是接下来的两个术语。因此,每次迭代都会重新分配已经计算过的斐波那契数,并添加另外两个元素,这将导致二次运行时间。将 b 放在 a 的前面会更有效。您将反向生成斐波那契数列,但运行时间将是线性的。如果您希望序列按升序排列,则可以在末尾对列表进行 reverse

请注意,以相反的顺序构建列表允许您使用 Code-Guru 的模式匹配思想轻松获得序列的最后两项。

对于 2),请注意,在整个计算完成之前,您无法获取列表的第一个元素。与以下序列的惰性生成进行比较:

fibs = 0 : (go 0 1)
  where go a b = b : go b (a+b)

尽管看起来递归从未停止,但 fibs 只会根据需要进行评估。例如,fibs !! 3 只调用 go 几次。

关于Haskell:改进我的尾递归斐波那契实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11656507/

10-12 02:29