你的帕斯卡三角算法是不正确的,但可能你还没有写完,所以我不会告诉你如何写一个正确的算法,只是告诉你如何阻止堆栈溢出。
编辑:maksimov 是对的,因为忘记将else
序列包装在大括号中,您只是使第一个表达式有条件,这意味着第二个表达式总是被评估并无限循环到堆栈溢出中。但是,添加大括号只会将堆栈溢出的 100% 概率更改为堆栈溢出的可能性,因为对pascal
函数的调用不在尾部位置。要消除堆栈溢出的风险,您必须进行进一步的修改,如下所述...
递归函数可以通过使用尾递归来避免堆栈溢出。但是,要使其正常工作,递归调用必须位于tail 位置。也就是说,递归调用必须是函数返回之前要执行的最终表达式,并且它的值必须不加修改地返回,一直返回堆栈到第一次调用。由于您的计算使用pascal(r, c-1) * (r-c)/c
,因此您总是在返回修改后的结果之前修改返回的值,因此调用不在尾部位置。您需要修改您的函数,以便当它最终返回时,它无需修改即可给出正确的结果。最终结果应该有这个基本的形状......
def pascal(c: Int, r: Int): Int = {
...
if (c <= 0) 1 else pascal(..., ...)
}
你会发现这样做的唯一方法是在你的 pascal 函数中定义一个局部函数并让它进行递归......
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
函数不是溢出的原因。代码中的两个顶级调用是连续的,不会相互干扰;如果一个完成,另一个也将完成。如果第一个失败,第二个也会失败(删除第一个不会阻止第二个失败)。