按: 本文书于半年前,近日清理电脑内容,暂列于此。
尾递归优化
每一次递归调用都会在栈区引入新的一层方法栈。如递归求解fabonacci值。可写如下实现:
def fabonacci(n)
return n if n < 2
return fabonacci(n-1) + fabonacci(n-2)
end
这里调用一次fabonacci(n)将导致fabonacci(n-1)、fabonacci(n-2) 入栈。fabonacci(n-1)也会将fabonacci(n-2)、fabonacci(n-3)入栈。这样,递归次数将以指数增长
➜ expace ruby -rprofile fabonacci_tail.rb 1
% cumulative self self total
time seconds seconds calls ms/call ms/call name
0.00 0.00 0.00 2 0.00 0.00 Object#fab
0.00 0.00 0.00 1 0.00 0.00 Object#fab_recur
➜ expace ruby -rprofile fabonacci_tail.rb 2
% cumulative self self total
time seconds seconds calls ms/call ms/call name
0.00 0.00 0.00 3 0.00 0.00 Object#fab
0.00 0.00 0.00 3 0.00 0.00 Object#fab_recur
➜ expace ruby -rprofile fabonacci_tail.rb 4
% cumulative self self total
time seconds seconds calls ms/call ms/call name
0.00 0.00 0.00 5 0.00 0.00 Object#fab
0.00 0.00 0.00 9 0.00 0.00 Object#fab_recur
➜ expace ruby -rprofile fabonacci_tail.rb 8
% cumulative self self total
time seconds seconds calls ms/call ms/call name
0.00 0.00 0.00 9 0.00 0.00 Object#fab
0.00 0.00 0.00 67 0.00 0.00 Object#fab_recur
➜ expace ruby -rprofile fabonacci_tail.rb 16
% cumulative self self total
time seconds seconds calls ms/call ms/call name
87.50 0.07 0.07 3193 0.02 0.24 Object#fab_recur
0.00 0.08 0.00 17 0.00 0.00 Object#fab
➜ expace ruby -rprofile fabonacci_tail.rb 24 1 % cumulative self self total
time seconds seconds calls ms/call ms/call name
84.18 3.14 3.14 150049 0.02 0.41 Object#fab_recur
0.00 3.73 0.00 25 0.00 2.80 Object#fab
以上是求fabonacci(n)时的递归次数统计。 为什么没有fab(32),原因是fab(32)在本环境下profile要很长时间。故未列出。
由此可见,尾递归优化十分有效。
附 测试源代码
➜ expace cat fabonacci_tail.rb
def fab(n, a, b)
return a if n < 1
fab(n-1, b, a+b)
end
def fab_recur(n)
return n if n < 2
fab_recur(n-1) + fab_recur(n-2)
end
n=ARGV[0].to_i
fab(n,0,1)
fab_recur(n)
尝试使用了fact尾递归,似乎没有效果。