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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  1. fs@ubuntu:~/qiang/digui$ ./digui1  
  2. 1 1 2 3 5 8 13 21   


递归的条件:

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

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

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

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

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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$   


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java判断两个Date是不是同一天

From: https://blog.csdn.net/xingchenbingbuyu/article/details/82734695 Java判断两个Date是不是同一天 1. 利用Calendar Calendar cal1 Calendar.getInstance(); Calendar cal2 Calendar.getInstance(); cal1.setTime(date1); cal2.setTime(date2); boolean sameDay ca…

js二级下拉被flash档住的解决办法

在<object></object>及以内的代码加入到<script>标签对内<script language"javascript" type"text/javascript"> <param name"wmode" value"transparent" />//背景透明 </script> 转载于:https:/…

iOS:以前笔记,未整理版。太多了,先放着吧。。。。。。。

1、**************************************************************** 单例共享 **************************************************************** 单例 共享信息 .m static OneT *newone nil; (instancetype)shalldata { if (newone nil) { newone [[OneT alloc]init]…

C语言经典编程题--哥德巴赫猜想 、完数 、猜数字等

一、 验证歌德巴赫猜想&#xff1a;任意一个不小于6的偶数都可以表示成两个素数的和。从键盘任意给一个符合条件的数&#xff0c;输出相应的两个素数。 素数&#xff1a;指在一个大于1的自然数中&#xff0c;除了1和此整数自身外&#xff0c;没法被其他自然数整除的数 代码如下…

Calendar的DAY_OF_MONTH, DAY_OF_YEAR, DATE的区别

From: https://blog.csdn.net/weixin_34233679/article/details/87286628 cal1.add(Calendar.DAY_OF_MONTH,1); cal1.add(Calendar.DAY_OF_YEAR,1); cal1.add(Calendar.DATE,1); 就单纯的add操作结果都一样&#xff0c;因为都是将日期1 就没有区别说是在月的日期中加1还是…

Cisco网络防火墙配置方法

这篇文章主要介绍了Cisco网络防火墙配置方法,需要的朋友可以参考下  由于网络防火墙默认禁止所有的通信&#xff0c;因为&#xff0c;只有对其进行适当配置后&#xff0c;才能实现正常的网络通信。  如何配置Cisco网络防火墙  1.进入全局配置模式  ciscoasa#configure …

linux远程登录三种方式telnet,ssh,vnc

linux远程连接三种方式telnet&#xff0c;ssh&#xff0c;vnctelnet和ssh服务只能实现基于字符界面的远程控制&#xff0c;如果要基于图形界面进行远程控制&#xff0c;可以借助免费的VNC来完成。一、telnet连接1.首先进入终端&#xff0c;查看是否安装了telnet服务。linux默认…

老司机学习MyBatis之如何通过select返回Map

From: https://blog.csdn.net/Gaomb_1990/article/details/80638177 一、案例 当要查询的结果是一个Map的时候&#xff0c;这里分为两种情况&#xff1a; ①返回单条记录 <select id"getUserByIdReturnMap" resultType"map"> select id, log…

大数据之Yarn——Capacity调度器概念以及配置

试想一下&#xff0c;你现在所在的公司有一个hadoop的集群。但是A项目组经常做一些定时的BI报表&#xff0c;B项目组则经常使用一些软件做一些临时需求。那么他们肯定会遇到同时提交任务的场景&#xff0c;这个时候到底如何分配资源满足这两个任务呢&#xff1f;是先执行A的任务…

C#基于Socket的简单聊天室实践

序&#xff1a;实现一个基于Socket的简易的聊天室&#xff0c;实现的思路如下&#xff1a; 程序的结构&#xff1a;多个客户端一个服务端&#xff0c;客户端都是向服务端发送消息&#xff0c;然后服务端转发给所有的客户端&#xff0c;这样形成一个简单的聊天室功能。 实现的细…

C/C++经典面试题

面试题1&#xff1a;变量的声明和定义有什么区别 为变量分配地址和存储空间的称为定义&#xff0c;不分配地址的称为声明。一个变量可以在多个地方声明&#xff0c;但只能在一个地方定义。加入extern修饰的是变量的声明&#xff0c;说明此变量将在文件以外或在文件后面部分定义…

Java跳出多重循环

From: https://www.cnblogs.com/fastfn/p/9777067.html 场景&#xff1a;很多的时候需要做到跳出多重循环&#xff0c;而在Java中虽然后goto关键字&#xff0c;但是是保留字&#xff0c;并没有启用。而在处理分支结构的if...else,switch...case,好像都达不到想要的效果。 作为…

CCF 节日

问题描述有一类节日的日期并不是固定的&#xff0c;而是以“a月的第b个星期c”的形式定下来的&#xff0c;比如说母亲节就定为每年的五月的第二个星期日。现在&#xff0c;给你a&#xff0c;b&#xff0c;c和y1, y2(1850 ≤ y1, y2 ≤ 2050)&#xff0c;希望你输出从公元y1年到…

回文数算法

1、回文数&#xff1a;一种数字&#xff0c;如&#xff1a;12321, 这个数字正读是12321&#xff0c;倒读也是12321&#xff0c;即&#xff1a;将这个数的数字按相反的顺序重新排列后&#xff0c;所得到的数和原来的数一样。回文数判别算法&#xff08;java实现&#xff09;impo…

深入了解scanf() getchar()和gets()等函数之间的区别

----------------------------------------------------| 问题描述一&#xff1a;&#xff08;分析scanf()和getchar()读取字符&#xff09; |-------------------------------------------------- scanf(), getchar()等都是标准输入函数&#xff0c;一般人都会觉得这几个函数…

java基础集合简介Map(三)下

From: https://www.cnblogs.com/douyu2580860/p/8358768.html --Map接口简介 今天来看一看map集合&#xff0c;map映射接口&#xff0c;用于存放键值对&#xff0c;<key,value>&#xff0c;通过key来查找value,顾名思义key不能为空&#xff0c;唯一且不重复&#xff0c;不…

横向量与矩阵的乘积

设Tj(Tj1, Tj2, ..., Tjn)为横向量。而iδ是Tj中第δ位不为零的元素&#xff0c;1≤δ≤z。 令hjTjH, 则hj是TH的第j行。且有 hjΣ(ki1, i2, ..., iz)Tj,kHk. 从上式看&#xff0c; &#xff08;1&#xff09;可以将横向量的第k位视为右边矩阵第k行是否叠加的控制信号。 &#…

MySQL日期时间函数大全(转)

DAYOFWEEK(date) 返回日期date是星期几(1星期天,2星期一,……7星期六,ODBC标准)mysql> select DAYOFWEEK(1998-02-03);   -> 3 WEEKDAY(date)  返回日期date是星期几(0星期一,1星期二,……6 星期天)。 mysql> select WEEKDAY(1997-10-04 22:23:00);   -> 5 my…

C语言常见错误

对于刚学编程&#xff0c;刚接触C的新手来说&#xff0c;编译运行报错是最头疼的一件事&#xff0c;爆出一堆英文&#xff0c;英语差一点的又不知道什么意思&#xff0c;所以也不知道如何去改&#xff0c;在此&#xff0c;我给大家传一份常见错误中英文对照表及简单解释&#x…

screen 断开 screen -r 不能进入断开的会话

From: https://www.wrox.org/archives/541 screen意外断开后screen -r *** 命令不能进入断开的会话&#xff0c;出现如下提示&#xff1a; There is a screen on: 11103.*** (Attached) There is no screen to be resumed matching ***. 这个时候可以用下面这条命令进入&…