你的帕斯卡三角算法是错误的,但可能你还没写完,所以我不会告诉你如何写一个正确的算法,只是告诉你如何阻止堆栈溢出。
编辑:maksimov 是对的,因为忘记将 else 序列括在大括号中,您只是使第一个表达式有条件,这意味着第二个表达式总是被评估并无限循环到堆栈溢出。但是,添加大括号只会将堆栈溢出的 100% 概率更改为堆栈溢出的可能性,因为对 pascal 函数的调用不在尾部位置。要消除堆栈溢出的风险,您必须进行进一步的修改,如下所述...
递归函数可以通过使用tail recursion 来避免堆栈溢出。但是,要使其正常工作,递归调用必须在tail position 中。也就是说,递归调用必须是函数返回之前要执行的最终表达式,并且必须不加修改地返回它的值,一直返回堆栈到第一次调用。由于您的计算使用pascal(r, c-1) * (r-c)/c,因此您总是在返回修改后的结果之前修改返回的值,因此调用not 在尾部位置。您需要修改您的函数,以便当它最终返回时,它无需修改即可给出正确的结果。最终的结果应该是这个基本的形状...
def pascal(c: Int, r: Int): Int = {
...
if (c <= 0) 1 else pascal(..., ...)
}
你会发现这样做的唯一方法是在你的 pascal 函数中定义一个本地函数并让 that 进行递归......
def pascal(c: Int, r: Int): Int = {
def loop(...): Int = ... match {
case ... => 1
case ... => x + y
case ... => loop(...)
case _ => loop(...)
}
...
if (c <= 0) 1 else loop(...)
}
这是因为递归函数必须检查状态以确定它是否解决了最终问题或问题中的子任务。状态可以是传递给loop 的额外参数或在pascal 顶层定义的本地变量
只有将递归安全地移动到本地函数中,才能安全地执行 maksimov 建议的操作
var p = if (c <= 0) 1 loop(...)
println(p)
p
您可以安全地执行此操作,因为 递归 调用都发生在 loop 内部并且都(如果您使用我的模板)在尾部位置。
需要明确:连续两次调用您的 pascal 函数并不是导致溢出的原因。代码中的两个顶级调用是连续的,不会相互干扰;如果一个完成,另一个也将完成。如果第一个失败,第二个也会失败(删除第一个不会阻止第二个失败)。