递归时堆栈级别太深(SystemStackError)

时间:2017-05-03 21:43:26

标签: ruby

我想进行这个简单的计算,但它抱怨堆栈不够深,即使是n的非常小的数字,例如4.其他类似主题的SO帖子建议尾递归,但那不是'这里适用,因为只有在达到基本情况时才会添加累积值。

RubyVM::InstructionSequence.compile_option = {
:tailcall_optimization => true,
:trace_instruction => false
}

def recursively_count_paths(x , y, n)
 if x == n &&  y == n
  return 1
  puts " we got a path people"
 elif x == n
  puts "x is done"
  return recursively_count_paths(x, y + 1, n)
 elif y == n
  puts "y is done"
  return recursively_count_paths(x + 1, y, n)
 else
 return (recursively_count_paths(x + 1, y, n) + 
recursively_count_paths(x, y + 1, n))
 end  
end

recursively_count_paths(0, 0, 20)

我不应该在其他情况下返回吗?

1 个答案:

答案 0 :(得分:3)

在这种情况下尾部递归无关紧要。由于您多次递归调用该方法,因此编译器无法进行该优化。大多数这些电话都是不必要的。我能够将您的代码重写为:

def recursively_count_paths(x, y, n)
  return 0 if x > n or y > n
  return 1 if x == n &&  y == n
  return recursively_count_paths(x+1, y, n) + recursively_count_paths(x, y+1, n)
end

第一行查找超出范围的路径,不计算那些路径。第二行相当于您的第一个if语句。如果路径已完成,则返回1。最后一行与最终的return语句相同,只是将所有路径向北添加,所有路径都向东移动。由于我们两次调用recursively_count_paths,尾调用优化仍然无济于事。

如果使用n = 20运行它,您可能会注意到它需要一段时间。这是因为随着网格大小的增加,该算法呈指数级增长。那是因为你一遍又一遍地计算相同的子路径。它也是Project Euler Problem 15,所以我不会在这里提供我的解决方案。不过,我会给你一个提示:保存你的工作。