Linux C学习---递归函数

最近学习到了递归,刚开始看,真是头大,函数里面嵌套其本身,到底是怎么个流程啊?

现在,咱们先了解下递归函数的数学原理:

高中的时候就出现很多递归函数,应该是在“级数”那里的习题中出现的,而且还不少。还是从例子开始吧: 

f(x)=f(x-1)+x*x ,其中x>0f(0)=0f(4)
:  由于f(0)=0:
x=1  f(1)=f(0)+1*1=1;
x=2  f(2)=f(1)+2*2=5;
x=3  f(3)=f(2)+3*3=14;
x=4  f(4)=f(3)+4*4=30;
所以, f(4)=30.
上学的时候,可能会这样做出来。 

f(x)=f(x-1)+x*x ,其中x>0f(0)=0就是一个递归函数,它用到了f(x)是用f(x-1)定义的。细心的人还可以发现x>0f(0)=0也是函数的一部分:
x>0提供一个递归区间,而f(0)=0提供了一个初始条件(思维方向不同,在电脑思维中这个条件为终止条件,详见下文)
或许大家觉得和我们课堂上的递归还是有点不同,不同在哪呢? 

这就是人脑和电脑的区别: 
电脑不会直接去找初始条件去向问题递推。 
而是从问题出发,递推下去,直到找到终止条件(解题时的初始条件)

电脑思维
f(4)=f(3)+4*4; 
f(3)=f(2)+3*3 
f(2)=f(1)+2*2 
f(1)=f(0)+1*1 
f(0)=0;                                  //终止条件
f(1)=f(0)+1*1=1; 
f(2)=f(1)+2*2=5; 
f(3)=f(2)+3*3=14; 
f(4)=f(3)+4*4=30; 

这个是电脑的思维过程,也就是计算过程,不会在前台显示出来。 
“遇到问题,解决问题,输出结果”——这是电脑处理问题的流程。 
关键在于,怎么写个递归函数让电脑认识。 
明白递归函数的定义,其实很简单。 

递归函数有三个充分条件:第一是函数体,第二是递归区间,第三个是终止条件

只要在代码中全部申明出来,一个递归函数的就写出来了。
       

上面的递归函数的就可以写出下面的代码:

[cpp]  view plain  copy
  1. function squaresum($x){   
  2.         if($x>0)                                                   //递归区间   
  3.                $result=squaresum($x-1)+$x*$x;        //函数体   
  4.         elseif($x=0)                                              //终止条件   
  5.                return $result=0;   
  6.         return $result;   
  7. }   
  8. echo squaresum(4); //输出30   


 

其中用到了if...elseif…语句,这就是来声明递归函数的递归区间终止条件(x>0f(0)=0)的。

现在在来写一个正整数nn!的递归函数就思路很明确了。 
分析:正整数n , f(n)=n!  =>  
函数体:f(n)=n*f(n-1)  递归区间:n.> 1    终止条件:n=1

[cpp]  view plain  copy
  1. function rank($n)  
  2. {   
  3.         if($n>1)   
  4.                $result=$n*rank($n-1);   
  5.         elseif($n=1)   
  6.                return $result=1;   
  7.         return $result.'<br>';   
  8. }   




由此我们可以发现当要写一个递归函数,找到终止条件,一个递归函数就很明朗了,剩下就是语法问题了

 

到linux C这块,我们做一个例题:

例:求斐波那契数列第n项。斐波那契数列的第一项和第二项是1,后面每一项是前两项之和,即1,1,2,3,5,8,13,。。。

下面程序采用直接递归调用:

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. long fib(int n)  
  4. {  
  5.     if(n == 0 || n == 1)  
  6.         return 1;  
  7.     else  
  8.         return (fib(n-1)+fib(n-2));  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int i;  
  14.   
  15.     for(i = 0;i < 8;i++)  
  16.         printf("%ld ",fib(i));  
  17.     printf("\n");  
  18.   
  19.     return 0;  
  20. }  


程序执行结果如下:

[cpp]  view plain  copy
  1. fs@ubuntu:~/qiang/digui$ ./digui1  
  2. 1 1 2 3 5 8 13 21   


递归的条件:

上面已经简单提到,现在再说明一下

一个问题能否用递归来实现,看其是否有如下特点:

1、须有完成函数任务的语句。

例如:下面的代码定义了一个递归函数

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. void count(int val)  
  4. {  
  5.     if (val > 1)  
  6.         count(val - 1);  
  7.     printf("OK:%d\n",val);  
  8. }  



该函数的任务是在输出设备上显示”ok: 整数值“。

2、一个任务是否能够避免递归调用的测试。

例如,上面的代码中,语句"if (val  > 1)"便是一个测试,如果不满足条件,就不进行递归调用。

3、一个递归调用语句

该递归调用语句的参数应该逐渐逼近不满足条件,以至最后断绝递归。

例如,上面的代码汇总,语句 "if( val > 1)"便是一个递归调用,参数在渐渐变小,这话总发展趋势能使测试 "if (val > 1)"最终不满足。

4,、先测试,后递归调用

在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,满足了条件,才可以递归。

例如,下面的代码无限制的调用函数自己,造成无限制递归,终将使栈空间溢出;

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. void count(int val)  
  4. {  
  5.     count(val - 1);//无限制递归  
  6.          if (val > 1)  
  7.         printf("OK:%d\n",val);  
  8. }  


下面是完整程序:

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2.   
  3. void count(int val)  
  4. {  
  5.     if (val > 1)  
  6.         count(val - 1);  
  7.     printf("OK:%d\n",val);  
  8. }  
  9.   
  10. int main()  
  11. {  
  12.     int n = 10;  
  13.   
  14.     count(n);  
  15.   
  16.     return 0;  
  17. }  

 

程序执行结果如下:

[cpp]  view plain  copy
  1. fs@ubuntu:~/qiang/digui$ vi digui2.c  
  2. fs@ubuntu:~/qiang/digui$ gcc -o digui2 digui2.c   
  3. fs@ubuntu:~/qiang/digui$ ./digui2  
  4. OK:1  
  5. OK:2  
  6. OK:3  
  7. OK:4  
  8. OK:5  
  9. OK:6  
  10. OK:7  
  11. OK:8  
  12. OK:9  
  13. OK:10  
  14. fs@ubuntu:~/qiang/digui$   


递归的应用会继续更新,比如在二叉树的遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值