#include<stdio.h>
/*
如果该函数中所有的递归调用形式逗出现在函数的末尾,则该函数是尾递归的
尾递归函数的特点是在回归过程中不用做任何操作
编译器检测到一个函数是尾递归的时候,
他就覆盖在当前的活动记录而不是在栈中再创建一个新的活动记录,
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递归(尾递归)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
相关阅读更多精彩内容
- 递归(Recursive)是指自己方法内部调用自己 如求 1- n(n>1)之间的和: 这是使用递归的方式求和,很...
- 递归 使用递归函数需要注意防止栈溢出问题。在计算机中函数调用是通过栈(stack)这种数据结构实现的,每当进入一个...