递归函数

定义

直接或间接调用函数本身的函数称为递归函数

递归是函数式编程的特点,也是优雅地实现很多算法的强大工具。在函数式编程中递归是实现“循环”的唯一方法,这是因为你无法修改循环变量


缺点

  1. 反复调用函数带来的开销;
  2. 栈溢出的风险。

尾递归

在递归函数中,若递归调用是整个函数中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归函数就是尾递归

尾递归是一种能把函数优化为循环的最重要的一种递归,可以消除递归函数潜在的栈溢出风险,并消除函数调用开销进而提升效率。

JVM和许多其它语言环境目前并不对尾递归做优化,但scalac则可以。


实例

import scala.annotation.tailrec

def factorial(i: BigInt) = {
  @tailrec
  def fact(i: BigInt, accumulator: BigInt): BigInt = {
    if(1 == i) accumulator
    else fact(i - 1, i * accumulator)
  }

  fact(i, 1)
}

标记@tailrec添加到尾递归函数时,编译器会对其做尾递归优化。若添加此标记的函数并不是尾递归函数,则编译器会抛出错误。

当一个调用了自身的方法,有可能被子类型中的同名方法覆写时,尾递归是无效的。所以,尾递归的方法必须用private或final关键字声明,或者将其嵌套在另一个方法中

Scala采用的是局部作用域类型推断,无法推断出递归函数的返回类型。因此需要显式写出其返回类型

定义一个嵌套的尾递归函数,将累加值作为参数,是将很多普通递归算法转化为尾递归的实用技巧


Trampoline类型递归函数

Trampoline(原意“蹦床”):是指通过依次调用各个函数完成一系列函数之间的循环,也即在多个函数之间反复来回调用。Scala库中的尾递归对象(scala.util.control.TailCalls)可以将trampoline转化为循环

import scala.util.control.TailCalls._

def isEven(xs: List[Int]): TailRec[Boolean] = {
  if(xs.isEmpty) done(true)
  else tailCall(isOdd(xs.tail))
}

def isOdd(xs: List[Int]): TailRec[Boolean] = {
  if(xs.isEmpty) done(false)
  else tailCall(isEven(xs.tail))
}

isEven((1 to 2).toList).result  //true

参考《Scala程序设计》第二版

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值