首页 > 代码库 > 线性递归和尾递归
线性递归和尾递归
线性递归,就是大家平常说的递归,线性递归函数的最后一步操作不是递归操作,将最终条件代入计算。在每次递归调用时,递归函数中的参数,局部变量等都要保存在栈中,当数据量很大的时候,会造成栈溢出。
尾递归,也就是线性迭代,尾递归函数的最后一步操作是递归,也即在进行递归之前,把全部的操作先执行完,这样的好处是,不用花费大量的栈空间来保存上次递归中的参数、局部变量等,这是因为上次递归操作结束后,已经将之前的数据计算出来,传递给当前的递归函数,这样上次递归中的局部变量和参数等就会被删除,释放空间,从而不会造成栈溢出。但是很多编译器并没有自动对尾递归优化的功能,也即当编译器判断出当前所执行的操作是递归操作时,不会理会它究竟是线性递归还是尾递归,这样也就不会删除掉之前的局部变量和参数等。另外,尾部递归一般都可转化为循环语句。
我们用阶乘的例子来看这两者的区别:
阶乘: 5!=1*2*3*4*5 结果为:120
线性递归:
long Rescuvie(long n)
{
return(n == 1) ? 1 : n * Rescuvie(n - 1);
}
调用过程如:
当n = 5时
对于线性递归, 他的递归过程如下:
Rescuvie(5)
开始调用
{5 * Rescuvie(4)}
{5 * {4 * Rescuvie(3)}}
{5 * {4 * {3 * Rescuvie(2)}}}
{5 * {4 * {3 * {2 * Rescuvie(1)}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120
尾递归:
long TailRescuvie(long n, long a) {
return(n == 1) ? a : TailRescuvie(n - 1, a * n);
}
对于尾递归, 他的递归过程如下:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
阶乘: 5!=1*2*3*4*5 结果为:120
线性递归:
long Rescuvie(long n)
{
return(n == 1) ? 1 : n * Rescuvie(n - 1);
}
调用过程如:
当n = 5时
对于线性递归, 他的递归过程如下:
Rescuvie(5)
开始调用
{5 * Rescuvie(4)}
{5 * {4 * Rescuvie(3)}}
{5 * {4 * {3 * Rescuvie(2)}}}
{5 * {4 * {3 * {2 * Rescuvie(1)}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120
尾递归:
long TailRescuvie(long n, long a) {
return(n == 1) ? a : TailRescuvie(n - 1, a * n);
}
对于尾递归, 他的递归过程如下:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
尾递归易于在编译器层面优化。如果编译器未作优化,效果和线性递归差不多。
分别用线性递归和尾递归来解决经典的猴子吃桃问题
猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个。第二天早上又将剩下的桃子吃了一半,还是不过瘾又多
吃了一个。以后每天都吃前一天剩下的一半再加一个。到第10天刚好剩一个。问猴子第一天摘了多少个桃子?
线性递归方式
#include <iostream>using namespace std;int AllSum(int day){ if(day==10) return 1; else return 2*AllSum(day+1)+2;}int main(){ int sum=AllSum(1); cout<<"第一天共摘了"<<sum<<"个桃子"<<endl; return 0;}
运行结果截图:
尾递归的实现方式
#include<iostream>using namespace std;int AllSum(int day,int total){ if(day==10) return total; else return AllSum(day+1,total*2+2);}int main(){ int sum=AllSum(1,1); cout<<"第一天共摘了"<<sum<<"个桃子"<<endl; return 0;}
运行结果截图:
关于线性递归和尾递归深度的研究学习可以参考 http://blog.zhaojie.me/2009/04/tail-recursion-explanation.html
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。