03递归(尾递归)

#include
/*
如果该函数中所有的递归调用形式逗出现在函数的末尾,则该函数是尾递归的
尾递归函数的特点是在回归过程中不用做任何操作

编译器检测到一个函数是尾递归的时候,
他就覆盖在当前的活动记录而不是在栈中再创建一个新的活动记录,

So,我们写递归是时尽量写成尾递归的形式

*/

/*
计算阶乘,非尾递归形式
例如:F(4,1)

F(4)==>4*F(3)                                 F(4)=6*4=24(终止)
         F(3)==>3*F(2)                   F(3)=3*2
                  F(2)==>2*F(1)   F(2)=2*1
                  (递推结束)F(1)==>1(开始回归)

栈的操作是这样的:
n=4 n=4 n=4 n=4 | n=4 n=4 n=4
xxx xxx xxx xxx | xxx xxx xxx
--- --- --- --- | --- --- ---
n=3 n=3 n=3 n=3 | n=3 n=3
    xxx xxx xxx | xxx xxx
    --- --- --- | ---
    n=2 n=2 n=2 | n=2
        xxx xxx | xxx
        --- --- |
        n=1 n=1 |
            xxx |
                |
                |
                |
    递推阶段     |  回归阶段


*/
int fact(int n){
    if(n<0)
        return 0;
    else if(n==0)
        return 1;
    else if(n==1)
        return 1;
    else
        return n*fact(n-1);
}

/*
计算阶乘,尾递归形式,a(初始为1)维护递归层次的深度,避免了每次还需要将返回值再乘以n
例如:F(4,1)

F(4,1)==>F(3,4)                                      F(4,1)=24(结束)
         F(3,4)==>F(2,12)                     F(3,4)=24
                  F(2,12)==>F(1,24)   F(2,12)=24
                   (递推结束)F(1,24)==>24(开始回归)

恩,情况貌似是这样,但是给函数在回归过程中不需要做任何操作,所以是被编译器判定为尾递归。
编译器件按会进行优化直接在栈的当前活动记录上进行覆盖,使得使用的栈空降大大缩小。

所以你可以把它理解为这样
F(4,1)==>F(3,4)
         F(3,4)==>F(2,12)
                  F(2,12)==>F(1,24)
                   (递推结束)F(1,24)==>24结束

栈的操作是这样的(受到编译器优化)
n=4 a=1   n=3 a=2   n=2 a=12  n=1 a=24
xxxxxxx   xxxxxxx   xxxxxxxx  xxxxxxxx
-------   -------   --------  --------
n=3 a=4   n=2 a=12  n=1 a=24

显然节省了很对空间时间也节省了点
*/
int facttail(int n,int a){
    if(n<0)
        return 0;
    else if(n==0)
        return 1;
    else if(n==1)
        return a;
    else
        return facttail(n-1,n*a);
}

/*
测试
*/
int main(){
    int result1=fact(4);
    printf("result1: %d\n",result1);
    int result2=facttail(4,1);
    printf("result2: %d\n",result2);

    return 0;
}

你可能感兴趣的:(03递归(尾递归))