尾递归

尾递归的定义

如果一个函数的所有地柜形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归。当递归调用时整个函数中过最后执行的语句且它的返回值不属于表达式的一部分时,这个地柜调用就是尾递归。尾递归的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。

尾递归的原理

当编译器检测到一个函数是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。编译器可以做到这点,因为递归调用时当前活跃期内最后一条待执行的语句,于是这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率变得更高。

尾递归的实例
package com.fpc.Test;

public class TailRescuvie {
    //线性递归
    public int Rescuvie( int n) {
        return ( n == 1 )? 1 : n * Rescuvie(n - 1);
    }
    
    //封装用
    public int tailRescuvie( int n ) {
        return ( n == 0 ) ? 1 : tailRescuive( n , 1 );
    }
    //尾递归
    public int tailRescuive( int n , int a ) {
        return ( n == 1 ) ? a : tailRescuive( n - 1 , a * n);
    }
    
    public static void main( String[] args ) {
        TailRescuvie t = new TailRescuvie();
        System.out.println(t.Rescuvie(5));
        System.out.println(t.tailRescuvie(5));
        
    }
}

对于线性递归,他的递归过程如下:

  1. Rescuvie(5)
  2. {5*Rescuvie(4)}
  3. {5*{4*Rescuvie(3)}}
  4. {5*{4*{3*Rescuvie(2)}}}
  5. {5*{4*{3*{2*Rescuvie(1)}}}}
  6. {5*{4*{3*{2*1}}}}
  7. {5*{4*{3*2}}}
  8. {5*{4*6}}
  9. {5*{24}
  10. 120

对于尾递归,他的递归过程如下:

  1. tailRescuvie(5)
  2. tailRescuvie(5,1)
  3. tailRescuvie(4,5)
  4. tailRescuvie(3,20)
  5. tailRescuvie(2,60)
  6. tailRescuvie(1,120)
  7. 120

很容易看出,普通的线性递归比尾递归更加消耗资源,在实现上来说,每次重复的过程调用都是的调用链条不断加长,系统不得不使用栈进行数据保存和回复,而尾递归就不存在这样的问题,因为他的状态完全由n和a来保存。

转载于:https://www.cnblogs.com/fangpengchengbupter/p/7985682.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值