【问题标题】:Fibonacci in HaskellHaskell中的斐波那契
【发布时间】:2017-12-06 01:18:18
【问题描述】:

所以这是一个斐波那契项计算函数(在 Ruby 中):

def fibfast(n)
  xs = [0,1]
  (n-1).times do |i|
    next_term = xs.sum
    xs[0]=xs[1]
    xs[1]=next_term
   end
   return xs[1]
 end

我很确定它具有恒定的空间复杂度(它唯一存储的数据在 xs 中)和线性时间复杂度(它使用一个循环来计算序列的第 n 项)。

我的问题是,函数是递归的吗?它使用它计算的值来做更多的计算,但从不调用自己。我的另一个问题是,如何在 Haskell 中获得同样的时空紧凑性?我发现 Haskell 函数的空间复杂度大于 O(1),返回完整的术语列表,和/或它们的时间复杂度大于 O(n),因为它们使用典型的递归定义。

感谢任何想法,谢谢!

【问题讨论】:

  • 为什么递归定义的时间复杂度更高。
  • 递归定义的斐波那契函数需要更多的计算,我相信它的复杂度是O(2^n)。
  • @ZacharyBechnoefer:如果您使用 累加器,则不会。
  • 如果你同时从迭代切换到递归和从这个标准算法切换到朴素算法,那么是的,你得到 O(fib(n)) 时间复杂度。但是只是从迭代风格切换到递归风格——同时保持相同的算法——将保持相同的 O(n) 时间复杂度。

标签: haskell recursion complexity-theory fibonacci


【解决方案1】:

我的问题是,函数是递归的吗?它使用它计算的值来进行更多计算,但从不调用自身。

否:递归意味着某事物是根据自身定义的。 fibfast 函数不是根据自身定义的。

我的另一个问题是,如何在 Haskell 中获得同样的时空紧凑性?我发现 Haskell 函数的空间复杂度大于 O(1),返回完整的术语列表,和/或它们的时间复杂度大于 O(n),因为它们使用典型的递归定义。

您可以使用以下功能:

fibfast :: Int -> Int
fibfast n = fib' 0 1 n
    where fib' a b n | n <= 1 = b
                     | otherwise = fib' b (a+b) (n-1)

所以这里我们定义了一个递归函数fib' 并使用两个累加器a 和b 来存储序列中的最后两个值。每次迭代,两者都会更新,我们会减少必须执行的迭代次数,直到达到小于或等于 1 的数字 n,在这种情况下,我们返回第二个累加器。

问题可能是 Haskell 通常不会急切地评估表达式,而是懒惰地。所以它存储a+b 而不是计算a+b。结果,表达式树很快就会像a+b+a+b+a+b...,从而快速增长。例如,我们可以使用 bang 模式:

{-# LANGUAGE BangPatterns #-}

fibfast :: Int -> Int
fibfast n = fib' 0 1 n
    where fib' a !b !n | n <= 1 = b
                       | otherwise = fib' b (a+b) (n-1)

【讨论】:

  • 非常酷!你在某个特定的班级学习过这个吗?比如,算法设计之类的?谢谢!
  • @ZacharyBechhoefer:不。实际上,我首先在逻辑编程课程(Prolog)中了解了累加器。但是逻辑和函数式编程有一些共同的背景。
  • @ZacharyBechhoefer 这是(我敢肯定)在计算机程序的结构和解释 (SICP) 中教授的课程,在本书的早期——它实际上也使用斐波那契作为示例程序,比较迭代与递归 procedures 与 processes
猜你喜欢
  • 2015-01-06
  • 1970-01-01
  • 2011-02-17
  • 2018-07-03
  • 1970-01-01
  • 2011-12-12
  • 2011-09-27
  • 2012-10-24
相关资源
最近更新 更多