古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔
子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数
为多少?
首先我们先做一下分析:
第一个月一对兔子:
第二个月一对兔子:
第三个月两对兔子:
第四个月三对兔子:
第五个月五对兔子:
第六个月八对兔子:
.
.
.
.
以此类推,知道每个月的兔子的对数都是由前两个月兔子对数的和.并且我们可以给出函数
f(x) = f(x-1)+f(x-2)前提是x从第三个月开始,我们可以把前两个月兔子的对数作为已知情况处理。
因此产生了递归:
递归:简单的讲就是一个方法,该方法的作用就是自己调用自己,用上一次调用的结果作为参数继续调用直到找到出口,因此我们在使用递归调用时一定要注意:需要一个出口,一个入口:
递归特点:网上查到的
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
大致意思也就是这样,下面给出一个列子作为递归的简单使用.只要想通了,其实是用递归能节省很多的代码量
如果学过栈的都知道,这是一个先入后出的特点,用它来解释递归非常契合,比如如下的一个例子中,假如我们想知道第三个月的兔子的对数,那么我们就需要知道,第二个月兔子的对数,同时我们如果想知道第二个月的兔子对数,就要知道第一个月兔子的对数,因此我们将第三个月的兔子对数作为未知入栈,依次入栈第二个月,第一个月,当我们把第一个月兔子对数入栈其实我们已经知道第一个月兔子对数.作出栈处理,第一个月兔子对数知道,从而知道第二个月,第三个月.
但是我们需要注意的是一定要给递归留一个出口否则容易发生死循环.当然有些是不需要递归也能实现的。
接着上面的列子,我们给出一个方法参照:
int f(int x){
int current;
if (x <= 2) {
return 1;
}else{
current = f(x-1) +f(x-2);
return current;
}
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
printf("该月兔子的对数:%d\n",f(8));
}
return 0;
}