您的位置:首页 > 运维架构 > Linux

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;

这个是电脑的思维过程,也就是计算过程,不会在前台显示出来。

“遇到问题,解决问题,输出结果”——这是电脑处理问题的流程。

关键在于,怎么写个递归函数让电脑认识。

明白递归函数的定义,其实很简单。

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

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

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

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$


递归的应用会继续更新,比如在二叉树的遍历
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: