Fibonacci数的递归解释

时间:2013-12-29 17:34:51

标签: ruby algorithm recursion fibonacci

我找到了一个代码,用于确定数字是否为斐波纳契数。我希望有人能够更轻松地分解它。

def is_fibonacci?(i, current = 1, before = 0)  
  return true if current == i || i == 0
  return false if current > i
  is_fibonacci?(i, current + before, current)
end

is_fibonacci?(3) # => true
is_fibonacci?(4) # => false

我知道一个方法在递归中调用自身,并且需要有一个基本情况,但同样,我很难看到正在发生的事情。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:2)

最简单的可视化方法是逐步完成一个方法调用计算,假设我们想要评估is_fibonacci?(8),那么ruby将设置current = 1, before = 0,因为我没有覆盖默认值

然后,由于i不是0或8,它必须递归,因此会发生以下方法调用:

is_fibonacci?(8, 1, 1)
is_fibonacci?(8, 2, 1)
is_fibonacci?(8, 3, 2)
is_fibonacci?(8, 5, 3)
is_fibonacci?(8, 8, 5)

最后,is_fibonacci?(8, 8, 5)可以从i == current (8 == 8)开始终止,因此它返回true。

编辑:考虑这种递归的另一种方式是你的currentbefore参数正在'重建'斐波纳契序列,如果它们点击i,那么答案是真的,但如果它们超过i,那就错了。

答案 1 :(得分:1)

  1. 首先,它检查i(请求的数字)是否等于Fibonaccy计算的数字,该数字传递给current变量,或者为零。如果等于,则返回true

    return true if current == i || i == 0
    
  2. 第二次检查i是否低于current变量。如果是,则i var将永远不会成为斐波纳契数,因此返回false

    return false if current > i
    
  3. 至少我们调用计算下一个数字的下一个Fibonaccy数,作为第二个参数的当前和前一个数字的总和,以及下一步的第三个参数的前一个当前数字。

    is_fibonacci?(i, current + before, current)
    
  4. 请注意,最好的方法是将尾部递归(在您的示例中为shewn)扩展为循环。

答案 2 :(得分:1)

基本上,它是一个带3个参数的函数。

i - 您正在测试的数字,看它是否是序列的一部分。

current - 您正在测试的当前斐波那契数字,默认为1,因此您无需提供第二个参数。

before - 序列中current数字之前的斐波纳契数,默认为0,因此您无需提供第三个参数。

示例值

如果current5,则before3

如果current8,则before5

该函数比较第一个参数i的值,并查看它是否等于0current斐波那契值。如果它等于current0,则它是斐波纳契数(因为0是序列中的第一个数字)。

然后查看current是否大于i。如果它更大,则不在序列中。这是因为如果45值,则无法继续检查序列中是否current

如果这两种情况都不匹配,我们只需再次调用该函数,传递i的值,查找序列current + before中的下一个数字,以及before的值将是序列中的current数字。

示例:

i15current5before3。再次调用该函数时,它将调用

is_fibonacci?(i, current + before, current)

将评估为

is_fibonacci?(15, 5 + 3, 5

注意

Ruby有一个很好的语法,if可以在之后来发生

if a < b
    puts "#{a} is greater than #{b}"

完全相同
puts "#{a} is greater than #{b}" if a < b

它只是减少了行数,而且读起来更像英语。

答案 3 :(得分:1)

如果is_fibonacci?有两个值10144,您可以查看通话跟踪。它显然是计算斐波纳契数小于或等于给定值,然后在递归中进行比较。

  is_fibonacci?(10, current = 1, before = 0)
   is_fibonacci?(10, current = 1, before = 1)
    is_fibonacci?(10, current = 2, before = 1)
     is_fibonacci?(10, current = 3, before = 2)
      is_fibonacci?(10, current = 5, before = 3)
       is_fibonacci?(10, current = 8, before = 5)
        is_fibonacci?(10, current = 13, before = 8)
  is_fibonacci?(144, current = 1, before = 0)
   is_fibonacci?(144, current = 1, before = 1)
    is_fibonacci?(144, current = 2, before = 1)
     is_fibonacci?(144, current = 3, before = 2)
      is_fibonacci?(144, current = 5, before = 3)
       is_fibonacci?(144, current = 8, before = 5)
        is_fibonacci?(144, current = 13, before = 8)
         is_fibonacci?(144, current = 21, before = 13)
          is_fibonacci?(144, current = 34, before = 21)
           is_fibonacci?(144, current = 55, before = 34)
            is_fibonacci?(144, current = 89, before = 55)
             is_fibonacci?(144, current = 144, before = 89)
10 : false ,  144 : true

以下是为前10个斐波那契数字提供此输出的代码:

def fib(n)
  if n <= 0 then 1
  else
    fib(n-1) + fib(n - 2)
  end
end


def is_fibonacci?(i, current = 1, before = 0, level=0)  
  puts (" " * level) + "  is_fibonacci?(#{i}, current = #{current}, before = #{before})"
  if current == i || i == 0 then
    return true 
  elsif current > i then
    return false 
  else
    is_fibonacci?(i, current + before, current, level+1)
  end
end

(0..10).each do |i|
  n = fib(i)
  ifib =is_fibonacci?(i)
  nfib = is_fibonacci?(n)
  puts "#{i} : #{ifib} ,  #{n} : #{nfib}"
end