#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递归(尾递归)
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 递归(Recursive)是指自己方法内部调用自己 如求 1- n(n>1)之间的和: 这是使用递归的方式求和,很...
- 递归 使用递归函数需要注意防止栈溢出问题。在计算机中函数调用是通过栈(stack)这种数据结构实现的,每当进入一个...