Linux C学习---递归函数
2015-12-08 20:29
459 查看
最近学习到了递归,刚开始看,真是头大,函数里面嵌套其本身,到底是怎么个流程啊?
现在,咱们先了解下递归函数的数学原理:
高中的时候就出现很多递归函数,应该是在“级数”那里的习题中出现的,而且还不少。还是从例子开始吧:
f(x)=f(x-1)+x*x ,其中x>0且f(0)=0求f(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>0且f(0)=0就是一个递归函数,它用到了f(x)是用f(x-1)定义的。细心的人还可以发现x>0且f(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;
这个是电脑的思维过程,也就是计算过程,不会在前台显示出来。
“遇到问题,解决问题,输出结果”——这是电脑处理问题的流程。
关键在于,怎么写个递归函数让电脑认识。
明白递归函数的定义,其实很简单。
递归函数有三个充分条件:第一是函数体,第二是递归区间,第三个是终止条件,
只要在代码中全部申明出来,一个递归函数的就写出来了。
上面的递归函数的就可以写出下面的代码:
其中用到了if...elseif…语句,这就是来声明递归函数的递归区间和终止条件(x>0且f(0)=0)的。
现在在来写一个正整数n的n!的递归函数就思路很明确了。
分析:正整数n , f(n)=n! =>
函数体:f(n)=n*f(n-1); 递归区间:n.> 1; 终止条件:n=1;
由此我们可以发现当要写一个递归函数,找到终止条件,一个递归函数就很明朗了,剩下就是语法问题了
到linux C这块,我们做一个例题:
例:求斐波那契数列第n项。斐波那契数列的第一项和第二项是1,后面每一项是前两项之和,即1,1,2,3,5,8,13,。。。
下面程序采用直接递归调用:
程序执行结果如下:
递归的条件:
上面已经简单提到,现在再说明一下
一个问题能否用递归来实现,看其是否有如下特点:
1、须有完成函数任务的语句。
例如:下面的代码定义了一个递归函数
该函数的任务是在输出设备上显示”ok: 整数值“。
2、一个任务是否能够避免递归调用的测试。
例如,上面的代码中,语句"if (val > 1)"便是一个测试,如果不满足条件,就不进行递归调用。
3、一个递归调用语句
该递归调用语句的参数应该逐渐逼近不满足条件,以至最后断绝递归。
例如,上面的代码汇总,语句 "if( val > 1)"便是一个递归调用,参数在渐渐变小,这话总发展趋势能使测试 "if (val > 1)"最终不满足。
4,、先测试,后递归调用
在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,满足了条件,才可以递归。
例如,下面的代码无限制的调用函数自己,造成无限制递归,终将使栈空间溢出;
下面是完整程序:
程序执行结果如下:
递归的应用会继续更新,比如在二叉树的遍历
现在,咱们先了解下递归函数的数学原理:
高中的时候就出现很多递归函数,应该是在“级数”那里的习题中出现的,而且还不少。还是从例子开始吧:
f(x)=f(x-1)+x*x ,其中x>0且f(0)=0求f(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>0且f(0)=0就是一个递归函数,它用到了f(x)是用f(x-1)定义的。细心的人还可以发现x>0且f(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;
这个是电脑的思维过程,也就是计算过程,不会在前台显示出来。
“遇到问题,解决问题,输出结果”——这是电脑处理问题的流程。
关键在于,怎么写个递归函数让电脑认识。
明白递归函数的定义,其实很简单。
递归函数有三个充分条件:第一是函数体,第二是递归区间,第三个是终止条件,
只要在代码中全部申明出来,一个递归函数的就写出来了。
上面的递归函数的就可以写出下面的代码:
function squaresum($x){ if($x>0) //递归区间 $result=squaresum($x-1)+$x*$x; //函数体 elseif($x=0) //终止条件 return $result=0; return $result; } echo squaresum(4); //输出30
其中用到了if...elseif…语句,这就是来声明递归函数的递归区间和终止条件(x>0且f(0)=0)的。
现在在来写一个正整数n的n!的递归函数就思路很明确了。
分析:正整数n , f(n)=n! =>
函数体:f(n)=n*f(n-1); 递归区间:n.> 1; 终止条件:n=1;
function rank($n) { if($n>1) $result=$n*rank($n-1); elseif($n=1) return $result=1; return $result.'<br>'; }
由此我们可以发现当要写一个递归函数,找到终止条件,一个递归函数就很明朗了,剩下就是语法问题了
到linux C这块,我们做一个例题:
例:求斐波那契数列第n项。斐波那契数列的第一项和第二项是1,后面每一项是前两项之和,即1,1,2,3,5,8,13,。。。
下面程序采用直接递归调用:
#include <stdio.h> long fib(int n) { if(n == 0 || n == 1) return 1; else return (fib(n-1)+fib(n-2)); } int main() { int i; for(i = 0;i < 8;i++) printf("%ld ",fib(i)); printf("\n"); return 0; }
程序执行结果如下:
fs@ubuntu:~/qiang/digui$ ./digui1 1 1 2 3 5 8 13 21
递归的条件:
上面已经简单提到,现在再说明一下
一个问题能否用递归来实现,看其是否有如下特点:
1、须有完成函数任务的语句。
例如:下面的代码定义了一个递归函数
#include <stdio.h> void count(int val) { if (val > 1) count(val - 1); printf("OK:%d\n",val); }
该函数的任务是在输出设备上显示”ok: 整数值“。
2、一个任务是否能够避免递归调用的测试。
例如,上面的代码中,语句"if (val > 1)"便是一个测试,如果不满足条件,就不进行递归调用。
3、一个递归调用语句
该递归调用语句的参数应该逐渐逼近不满足条件,以至最后断绝递归。
例如,上面的代码汇总,语句 "if( val > 1)"便是一个递归调用,参数在渐渐变小,这话总发展趋势能使测试 "if (val > 1)"最终不满足。
4,、先测试,后递归调用
在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,满足了条件,才可以递归。
例如,下面的代码无限制的调用函数自己,造成无限制递归,终将使栈空间溢出;
#include <stdio.h> void count(int val) { count(val - 1);//无限制递归 if (val > 1) printf("OK:%d\n",val); }
下面是完整程序:
#include <stdio.h> void count(int val) { if (val > 1) count(val - 1); printf("OK:%d\n",val); }
int main()
{
int n = 10;
count(n);
return 0;
}
程序执行结果如下:
fs@ubuntu:~/qiang/digui$ vi digui2.c fs@ubuntu:~/qiang/digui$ gcc -o digui2 digui2.c fs@ubuntu:~/qiang/digui$ ./digui2 OK:1 OK:2 OK:3 OK:4 OK:5 OK:6 OK:7 OK:8 OK:9 OK:10 fs@ubuntu:~/qiang/digui$
递归的应用会继续更新,比如在二叉树的遍历
相关文章推荐
- 如何在Linux中查看所有正在运行的进程
- Centos root权限的变化
- Linux 的popen函数
- Linux rpm 命令参数使用详解[介绍和应用]
- Linux平台swift语言开发学习环境搭建
- Linux的介绍
- Linux负载均衡软件LVS之四(测试篇-完)
- Linux负载均衡软件LVS之二(安装篇)
- Linux负载均衡软件LVS之三(配置篇)
- linux系统快速查看进程pid的方法
- Linux负载均衡软件LVS之一(概念篇)
- Linux基础-查看文件与目录
- linux下的权限详解
- Linux系统的启动流程
- linux的引导过程和服务控制
- linux的引导过程和服务控制
- linux的引导过程和服务控制
- linux引导过程和服务控制
- linux引导过程和服务控制
- linux引导过程和服务控制