探索递归奥秘——阶乘、菲波那切数列 的递归实现、尾递归实现 与 迭代实现

尾递归:

即 写成尾调用形式的递归。

尾递归的结果只跟传入的参数有关,因此只需要用少量的变量记录参数变化,便能够轻易的改写成循环形式,

所以尾递归和循环等价,也即和迭代等价

递归 与 迭代 的关系:

递归:自己调用自己

迭代:A不停地调用B

递归中一定有迭代,

迭代中不一定有递归,

大部分情况下可以相互转化,

又因为递归浪费空间易造成栈溢出,所以能用迭代的就不用递归

//这是递归  
int funcA(int n)  
{  
    if(n > 1)  
       return n+funcA(n-1);  
    else   
       return 1;  
}  

//这是迭代  
int funcB(int n)  
{  
    int i,s=0;  
    for(i=1;i<n;i++)  
       s+=i;  
    return s;  
}  

尾调用:

无需返回的函数调用,即函数调用不处于参数的位置上。

Add(1,2), Mul(1,2)是尾调用;

Add(1, Mul(3,4))不是尾调用,因为函数Mul作为了函数Add的参数,

在计算Mul(3,4)之前需要保存状态,待Mul算完后把返回结果result送给Add计算Add(1,result)。

写成尾调用的形式 利于 编译器对函数调用 进行优化。

只要编译器判断某条语句是尾调用,编译器就不会保存状态。

代码——阶乘的3种实现方式

int factorial(int n,int count)// count:counter
{
    printf("%d --------- ",count);
    if(n<0){
        return -1;
    }else if(n==0 || n==1){
        return 1;
    }else{
        count++;
        return n*factorial(n-1,count);
    }
}

int tailed_factorial(int number, int result)
{
    if (number < 0)
        return -1;
    else if (number == 0)
        return 1;
    else if (number == 1)
        return result;
    else
        return tailed_factorial(number - 1, number * result);//在函数的参数上实现的乘法运算
}

int iteration_factorial(int number)
{
    int result = 1;

    if(number < 0){
        return -1;
    }else if(number == 0 || number == 1){
        return 1;
    }else{
        for(int i=1;i<=number;i++){
            result = result * i;
        }
    }

    return result;
}

递归过程的说明:

( Factorial 3 )

= ( 3 * ( Factorial 2 ) )

= ( 3 * ( 2 * ( Factorial 1 ) ) ),这需要用到3层栈结构

= ( 3 * ( 2 * 1 ) )

= ( 3 * 2 )

= 6

每个活跃期 计算 n倍的(n-1)!,

让n = n-1,持续这个过程直到n = 1为止。

每个活跃期的返回值都依赖于用n乘以下一个活跃期的返回值,

所以每次调用产生的栈帧必须保存在栈上,直到下一个调用的返回值确定。

尾递归过程的说明:

( TailedFactorial(3,1) )

= ( TailedFactorial(2,3 * 1) )

= ( TailedFactorial(1,2 * 3 * 1) )

= 2 * 3 * 1

实现上述过程最少可以用到1层栈结构,

而现代的编译器可以做到当检测到一个函数是尾递归的时候,

覆盖当前的活动记录即栈帧,而不是在其之上重新添加一个新的,这样就只用到1层栈。

这样使得栈空间大大缩减,使得实际的运行效率变得更高。


代码——斐波那契数列的3种实现方式 

// 0,1,1,2,3,5,8,13......
int fib(n)
{
    if(n < 0){
        return -1;
    }else if(n==0 || n==1){
        return n;
    }else{
        return fib(n-2)+fib(n-1);
    }
}

int tailed_fib(int first, int second, int arr_index, int result)
{
    if (arr_index < 0)
        return -1;
    else if (first ==0 && second == 1 && (arr_index == 0 || arr_index == 1))
        return arr_index;
    else if (arr_index == 1)
        return result;
    else
        return tailed_fib(second,first+second,--arr_index,first+second);//在函数的参数上实现的加法运算
}

int iteration_fib(int first,int second,int arr_index)
{
    if (arr_index < 0)
        return -1;
    else if (first ==0 && second == 1 && (arr_index == 0 || arr_index == 1))
        return arr_index;
    else{
        int result = 0;
        for(int i=arr_index;i>1;i--){
            result = first + second;
            first = second;
            second = result;
        }
        return result;
    }
}

对 菲波那切数列 尾递归 代码的实现 进行 详细点的改进:
可以通过 参数first和second自己设定 菲波那切数列的第一个、第二个元素
int corrected_tail_recursive_fib(int first, int second, int arr_index, int result)// should set result = 0
{
    if (arr_index < 0)
        return -1;
    else if (arr_index == 0){
        //printf("**\n");// don't execute
        return first;
    }
    else if (arr_index == 1){
        //printf("##\n");// don't execute
        return second;
    }
    else // arr_index > 1
        return tail_recursive_fib(second,first+second,--arr_index,first+second);//在函数的参数上实现的加法运算
}
/*
first = 3, second = 5, arr_index = 4, result = 0
tail_recursive_fib(5,3+5,3,3+5)
tail_recursive_fib(3+5,(3+5)+5,2,(3+5)+5)
tail_recursive_fib((3+5)+5,((3+5)+5)+(3+5)),1,((3+5)+5)+(3+5)))
return ((3+5)+5)+(3+5))
*/
// array index: 0,1,2,3, 4, 5, 6, 7,  8,  9
// array value: 0,1,1,2, 3, 5, 8, 13, 21, 34 ......
// array value: 3,5,8,13,21,34,55,89,144,233......

int corrected_iterative_fib(int first,int second,int arr_index)
{
    if (arr_index < 0)
        return -1;
    else if (arr_index == 0)
        return first;
    else if (arr_index == 1)
        return second;
    else{
        int result = 0; // 这种方法是在 这个地方 对result设定初始值0
        for(int i=arr_index;i>1;i--){
            result = first + second;
            first = second;
            second = result;
        }
        return result;
    }
}

int main()
{
    int first,second,array_index;
    printf("please input the value of var first,second,array_index\n");
    scanf("%d%d%d",&first,&second,&array_index);

    printf("corrected tail recursive Fibonacci result is %d\n",corrected_tail_recursive_fib(first,second,array_index,0));// let result = 0
    printf("corrected iterative Fibonacci result is %d\n",corrected_iterative_fib(first,second,array_index));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值