【发布时间】:2022-01-04 13:25:34
【问题描述】:
我知道,在使用 Loops 时,可变性会出现,并让事情难以追踪。但是在Scala中,递归被认为是循环的仅仅是因为可变性吗?
另外,我知道尾递归不会添加到您的调用堆栈中,但并非所有问题都可以使用尾递归解决,对吧?使用基于累加器的方法怎么样,它似乎也足以避免堆栈溢出情况?尾递归和基于累加器的递归方法之间有什么更好的性能?
简而言之,我有两个问题:
- 由于尾递归不能用于解决所有循环问题(或者可以吗?)循环不是更好还是某些特定用例的唯一解决方案?
- 尾递归和基于累加器的递归有什么区别?根据空间复杂度和调用堆栈占用情况,哪一种性能更高?
编辑 1:
在基于累加器的递归(因子函数)中转换的非尾递归函数(使用中间尾递归函数)示例:
没有累加器:
def factorial(n: Int): Int = {
if (n <= 1) 1
else n * factorial(n - 1)
}
带累加器:
def tailRecFactorial(n: Int): BigInt = {
@tailrec
def factorialHelper(x: Int, accumulator: BigInt): BigInt = {
if (x <= 1) accumulator
else factorialHelper(x - 1, x * accumulator)
}
factorialHelper(n, 1)
}
【问题讨论】:
-
你能举一个你认为基于累加器的递归的例子吗?
-
请注意,将尾递归函数中的某些参数称为“累加器”并不少见。
-
"既然尾递归不能用来解决所有的循环问题(或者可以吗?)" – 尾递归可以用来解决所有的循环问题,证明是微不足道:您可以在大约两行 Scala 中递归地实现
while。def myWhile(cond: () => Boolean)(body () => Unit) = if (cond()) { body(); myWhile(cond)(body) }或类似的东西。