Scala中的尾递归
递归是一种将问题分解为较小的子问题并针对每个问题调用自身的方法。也就是说,它只是意味着函数调用自身。尾递归函数比非尾递归函数更好,因为尾递归可以通过编译器进行优化。如果递归调用是函数完成的最后一件事,则称递归函数为尾递归。无需记录之前的状态。
对于尾递归函数,程序中将使用包import scala.annotation.tailrec
。
句法:
@tailrec
def FuntionName(Parameter1, Parameter2, ...): type = …
让我们通过例子来理解尾递归。
例子 :
// Scala program of GCD using recursion
import scala.annotation.tailrec
// Creating object
object GFG
{
// Function defined
def GCD(n: Int, m: Int): Int =
{
// tail recursion function defined
@tailrec def gcd(x:Int, y:Int): Int=
{
if (y == 0) x
else gcd(y, x % y)
}
gcd(n, m)
}
// Main method
def main(args:Array[String])
{
println(GCD(12, 18))
}
}
输出:
6
正如我们在上面的示例中看到的, @tailrec
用于 gcd函数,即尾递归函数。通过使用尾递归,无需记录 gcd函数的先前状态。
例子 :
// Scala program of factorial using tail recursion
import scala.annotation.tailrec
// Creating object
object GFG
{
// Function defined
def factorial(n: Int): Int =
{
// Using tail recursion
@tailrec def factorialAcc(acc: Int, n: Int): Int =
{
if (n <= 1)
acc
else
factorialAcc(n * acc, n - 1)
}
factorialAcc(1, n)
}
// Main method
def main(args:Array[String])
{
println(factorial(5))
}
}
输出:
120
在上面的代码中,我们可以使用@tailrec
注解来确认我们的算法是尾递归的。
如果我们使用这个注解并且我们的算法不是尾递归的,编译器就会报错。例如,如果我们尝试在上面的阶乘方法示例中使用此注解,我们将得到以下编译时错误。
例子 :
// Scala program of factorial with tail recursion
import scala.annotation.tailrec
// Creating object
object GFG
{
// Function defined
@tailrec def factorial(n: Int): Int =
{
if (n == 1)
1
else
n * factorial(n - 1)
}
// Main method
def main(args:Array[String])
{
println(factorial(5))
}
}
输出:
Could not optimize @tailrec annotated method factorial: it contains a recursive call not in tail position.