从Fibonacci到尾递归(tail recurrence)

     Fibonacci函数有两种很经典的实现

一种是以while为基础的:

public long Fib_Loop(int n)
{
     long b1 = 1, b2 = 1, temp, begin = 3;
     for (; begin <= n; ++begin)
     {
        temp = b1;
        b1 = b2;
        b2 = temp + b2;
     }
     return b2;
}

 一种是以递归为基础的:

public long Fib_Recur(int n)
{
    if (n == 1 || n == 2)     //line1
        return 1;     //line2
    else
        return Fib_Recur(n - 1) + Fib_Recur(n - 2);     //line 3
}

 很明显这种递归效率极低:

Fib(6) = Fib(5) + Fib(4);
     = Fib(4) + Fib(3) + Fib(3) + Fib(2);
     = Fib(3) + Fib(2) + Fib(2) + Fib(1) + Fib(2) + Fib(1) + Fib(2);
     = Fib(2) + Fib(1) + Fib(2) + Fib(2) + Fib(1) + Fib(2) + Fib(1) + Fib(2);
     = 8

       Notice that the first call on line 3,Fib(N-1),actually computes Fib(N-2) at some point.This information is thrown away and recomputed by the second call on line3.The amount of information thrown away componds recursively and results in the huge running time.This is perhaps the finest example of the maxim "Don't compute anything more than once" and should not scare you away from using recursion.

                                                                                      --《Data Structures and Algorithm Analysis》

另外一种高效率的递归:

public long Fib_Tail(int n)
{
      if (n == 1 || n == 2)
        return 1;
      else
        return Tail(n, 1, 1, 3);
}

//Typical help function...
private long Tail(int n, long b1, long b2, int begin)
{
      if (n == begin)
      {
        return b1 + b2;
      }
      else
        return Tail(n, b2, b1 + b2, begin + 1);
}

 使用尾递归,而且计算几乎完全发生在尾递归中。

 

再说到Scala中的尾递归。由于函数式编程提倡在函数体中不适用var,所以一般的while式的命令式代码(imperative code)是建议被替换的,也就是说你可能会先写出while形式的语句,然后对其进行一番考究,看其是否能转换为函数式的代码。同时,在Scala中,尾递归是会被编译器优化的(虽然编写尾递归是有许多的限制),使其能够达到一般while语句的执行效率。

 

def boom(x: Int): Int =
     if (x == 0) throw new Exception("boom!")
     else boom(x - 1) + 1

//This function is not tail recursive, because it performs an increment operation 
//after the recursive call.
 
def bang(x: Int): Int =
     if (x == 0) throw new Exception("bang!")
     else bang(x 1)

     A tail-recursive function will not build a new stack frame for each call; all calls will execute in a single frame.

     The Scala compiler detects tail recursion and replaces it with a jump back to the beginning of the function, after updating the function parameters with the new values.
     The moral is that you should not shy away from using recursive algorithms to solve your problem. Often, a recursive solution is more elegant and concise than a loop-based one. If the solution is tail recursive, there won’t be any runtime overhead to be paid.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值