Ruby 优化递归搜索

Ruby 优化递归搜索,ruby,optimization,recursion,fibonacci,Ruby,Optimization,Recursion,Fibonacci,我做了一个实验,对递归和迭代斐波那契序列进行计时。有没有更好的方法来提高递归方法的性能 require 'benchmark' def fibonacci_iterative(n) fib_numbers = [0, 1] iterate = n-1 iterate.times do number = fib_numbers[-2] + fib_numbers[-1] fib_numbers << number end p fib_numbers

我做了一个实验,对递归和迭代斐波那契序列进行计时。有没有更好的方法来提高递归方法的性能

require 'benchmark'

def fibonacci_iterative(n)
  fib_numbers = [0, 1]
  iterate = n-1
  iterate.times do
    number = fib_numbers[-2] + fib_numbers[-1]
    fib_numbers << number
  end
  p fib_numbers[-1]
end

def fibonacci_recursive(n)
  fib_number = 0
  if n == 0 || n == 1
    n
  else
    fib_number = fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
  end
end

puts Benchmark.measure {fibonacci_iterative(5)}
puts Benchmark.measure {fibonacci_recursive(5)}

5
  0.000000   0.000000   0.000000 (  0.000037)
  0.000000   0.000000   0.000000 (  0.000005)

puts Benchmark.measure {fibonacci_iterative(45)}
puts Benchmark.measure {fibonacci_recursive(45)}

1134903170
  0.000000   0.000000   0.000000 (  0.000039)
378.990000   0.330000 379.320000 (379.577337)
需要“基准测试”
def fibonacci_迭代(n)
fib_数=[0,1]
迭代=n-1
迭代时间
数字=光纤数[-2]+光纤数[-1]

fib_数值在计算递归斐波那契时,您可以尝试保存结果:

def fibonacci_recursive(n):
    def fib_rec(n, a, b):
        if n == 1:
            return a
        return fib_rec(n - 1, a + b, a)
    return fib_rec(n, 1, 0)
递归代码具有指数行为:O(phi^n),其中phi=(1+sqrt(5))/2


编辑:这是用Python编写的(没有看到Ruby标记)。翻译应该相当简单。

在计算递归斐波那契时,您可以尝试保存结果:

def fibonacci_recursive(n):
    def fib_rec(n, a, b):
        if n == 1:
            return a
        return fib_rec(n - 1, a + b, a)
    return fib_rec(n, 1, 0)
递归代码具有指数行为:O(phi^n),其中phi=(1+sqrt(5))/2


编辑:这是用Python编写的(没有看到Ruby标记)。应该相当简单地翻译。

长期运行时间不是递归的固有函数,但是当您有冗余的递归计算时,它通常会出现。可以使用一种称为“记忆”的技术来避免这种情况,即只计算一次值并将其列为表格以备将来使用

这是一个Fibonacci数的记忆递归实现,monkey被修补成Fixnum

class Fixnum
  @@fib_value = [0,1]

  def fib
    raise "fib not defined for negative numbers" if self < 0
    @@fib_value[self] ||= (self-1).fib + (self-2).fib
  end
end

0.fib     # => 0
1.fib     # => 1
2.fib     # => 1
5.fib     # => 5
100.fib   # => 354224848179261915075
class-Fixnum
@@fib_值=[0,1]
def纤维
如果self<0,则提出“fib未定义负数”
@@fib_值[self]| |=(self-1).fib+(self-2).fib
终止
终止
0.fib#=>0
1.fib#=>1
2.fib#=>1
5.fib#=>5
100.fib#=>35422484818179261915075
如果您真的想做得更大,请使用斐波那契算法,即O(logn):

class-Fixnum
def纤维
如果self<0,则提出“fib未定义负数”
自我零度?self:matrix_fib(self)[1]
终止
私有的
def矩阵纤维(n)
如果n==1
[0,1]
其他的
f=矩阵_fib(n/2)
c=f[0]*f[0]+f[1]*f[1]
d=f[1]*(f[1]+2*f[0])
n、 甚至?[c,d]:[d,c+d]
终止
终止
终止
45.fib#=>1134903170确认正确性

虽然输出超过2600 80列,但几乎可以立即计算
1000000.fib,而不会破坏递归堆栈。

长时间运行不是递归的固有函数,但在进行冗余递归计算时,经常会出现这种情况。可以使用一种称为“记忆”的技术来避免这种情况,即只计算一次值并将其列为表格以备将来使用

这是一个Fibonacci数的记忆递归实现,monkey被修补成Fixnum

class Fixnum
  @@fib_value = [0,1]

  def fib
    raise "fib not defined for negative numbers" if self < 0
    @@fib_value[self] ||= (self-1).fib + (self-2).fib
  end
end

0.fib     # => 0
1.fib     # => 1
2.fib     # => 1
5.fib     # => 5
100.fib   # => 354224848179261915075
class-Fixnum
@@fib_值=[0,1]
def纤维
如果self<0,则提出“fib未定义负数”
@@fib_值[self]| |=(self-1).fib+(self-2).fib
终止
终止
0.fib#=>0
1.fib#=>1
2.fib#=>1
5.fib#=>5
100.fib#=>35422484818179261915075
如果您真的想做得更大,请使用斐波那契算法,即O(logn):

class-Fixnum
def纤维
如果self<0,则提出“fib未定义负数”
自我零度?self:matrix_fib(self)[1]
终止
私有的
def矩阵纤维(n)
如果n==1
[0,1]
其他的
f=矩阵_fib(n/2)
c=f[0]*f[0]+f[1]*f[1]
d=f[1]*(f[1]+2*f[0])
n、 甚至?[c,d]:[d,c+d]
终止
终止
终止
45.fib#=>1134903170确认正确性

您可以几乎同时计算
1000000.fib
,而不会破坏递归堆栈,尽管输出超过2600行80列。

您在Ruby中的Fibonacci实现是正确的。您可以用以下方式重写它

def fib(n)
  if n < 2
    n
  else
    fib(n-1) + fib(n-2)
  end
end
为了好玩,这里有一个更紧凑、更独立的替代方案

def fib(n)
  $fibcache    ||= []
  $fibcache[n] ||= (n < 2 ? n : fib(n-1) + fib(n-2))
end
def fib(n)
$fibcache | |=[]
$fibcache[n]| |=(n<2?n:fib(n-1)+fib(n-2))
终止

另外,我只使用了一个全局变量作为示例来演示记忆模式。您应该使用更好的系统,全局变量在Ruby中几乎被认为是一种代码味道。

您在Ruby中的Fibonacci实现是正确的。您可以用以下方式重写它

def fib(n)
  if n < 2
    n
  else
    fib(n-1) + fib(n-2)
  end
end
为了好玩,这里有一个更紧凑、更独立的替代方案

def fib(n)
  $fibcache    ||= []
  $fibcache[n] ||= (n < 2 ? n : fib(n-1) + fib(n-2))
end
def fib(n)
$fibcache | |=[]
$fibcache[n]| |=(n<2?n:fib(n-1)+fib(n-2))
终止

另外,我只使用了一个全局变量作为示例来演示记忆模式。您应该使用更好的系统,全局变量在Ruby中几乎被认为是一种代码味道。

@DavidNehme示例是Java,而不是Ruby@DavidNehme示例是Java,而不是Ruby。