一.函数迭代V.S.函数递归
1.函数调用
2.函数迭代
3.函数递归
4.函数迭代与函数递归——相同点
5.函数迭代与函数递归——不同点
二.小蜜蜂问题
1.算法分析
2.斐波那契数列
3.字符串加法(略)
一.函数迭代V.S.函数递归:
最近学函数很大的感想是:一听讲解就恍然大悟,一自己做就不知如何排布。
什么是函数调用?什么是函数迭代?什么是函数递归?学的时候似乎分得很清,但是一做题就容易思维混乱,开始迭代递归混搭使用......
今天由小蜜蜂这题,我对迭代和递归有了些新的认识和感受,比较直观条目化,可以有效摆脱抽象,所以与大家分享~
1.函数调用:
通过函数语句,来抽调使用一个定义过的函数;
2.函数迭代:
2.1 本质:
通过循环的方式,来模拟递归的过程(可以理解为通过循环赋值的方式来达到递归的效果),但不是递归本身;
所以不应该在循环里再去调用函数自身,否则仍是一种不完全的递归,也许会减少一些重复劳动,但仍不能使效率有质的提升;
一定要思路清晰,避免递归、迭代混搭!
2.2 终止条件:
取决于循环的终止条件;
2.3 过程:
①必要的分类讨论(通过选择语句实现);
②主体部分:不断赋值给变量(需要能够找出普适的规律和普适的赋值方式)
+对变量进行完全相同步骤的重复(通过循环语句实现)
+返回最后一次循环的结果;
③其他部分:是一些特殊情况,通常比较简单,各自返回计算结果即可;
3.函数递归:
3.1 本质:
通过不断调用函数的方式,大事化小(自己找规律)/公式法(现成,较简单),
最终化为一种最简单的情况(进入另一分支),返回确定的值,
再由此层层返回至所求的情况;
也一样不要再嵌套循环,造成与迭代混搭的混乱写法;
3.2 终止条件:
将最简单的情况作为一个单独的分支,返回确定的值,
不断调用,最终一定会化为这种情况,从而终止;
3.3 过程:
①分类讨论,分出主体部分,特殊情况和最简单的情况(用于终止递归)
(通过选择语句实现);
②主体部分:找出相邻两数间的关系,在return后表达出来(通过函数调用实现+return实现)
+不断调用至最简单的情况,返回确定的值;
+从而层层返回确定的值,最终返回一个确定的结果;
③其他部分:是一些特殊情况,通常比较简单,各自返回计算结果即可;
4.函数迭代与函数递归——相同点
① 都需要终止条件;
② 都是为了实现一种递归思想;
5.函数迭代与函数递归——不同点
① 迭代——循环,不调用;
递归——调用,不循环;
② 迭代——主体部分返回最后一次循环的结果;
递归——主体部分有最简单的情况的确定的返回值,根据调用,逆向层层返回,得到确定结果;
③ 迭代--效率高,不重复劳动,但是有时难以实现,没有递归的思路简单;
递归--效率低,但思路简单,不能递归层次过深,会造成栈溢出;
二.小蜜蜂问题:
1.算法分析:
斐波那契数列+字符串加法
2.斐波那契数列:
其本质为斐波那契数列,只是描述的花哨;
斐波那契数列解释:
代码实现(两种方式):
函数迭代:(效率高,但因为循环是完全相同的步骤的重复,就需要能够找出普适的规律和普适的赋值方式)
#include <stdio.h>
long long route(int a, int b)
{
int i;
long long count = 2, tmp = 1,copy;
if (b == a + 1)
{
return 1;
}
else if (b == a + 2)
{
return 2;
}
else
{
for (i = a + 3; i <= b; i++)//主体部分(函数迭代);
{
copy = count;
count = count + tmp;
tmp = copy;
}
return count;
}
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
long long route_count = route(a, b);
printf("%lf\n", route_count);
return 0;
}
2.函数递归:(很直接,但是效率低,e.g.1-50那个测试用例要运行大约两分钟)
#include <stdio.h>
long long route(int a, int b)
{
if (b == a + 1)
{
return 1;
}
else if (b == a + 2)
{
return 2;
}
else
{
return route(a, b - 1) + route(a, b - 2);
}
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
long long count = route(a, b);
printf("%lld\n", count);
return 0;
}
效率低的原因分析:
3.迭代递归混搭(本质还是递归)
是思维极度混乱的产物,要摒弃!!!
#include <stdio.h>
long long route(int a, int b)
{
int i;
long long count = 2;
if (b == a + 1)
{
return 1;
}
else if (b == a + 2)
{
return 2;
}
else
{
for (i = a + 3; i <= b; i++)
{
count = count + route(a, i - 2);
}
return count;
}
}
3.字符串加法:
需使用的理由:因为测试用例1-100那个的结果数字过大,超过了long long型,错误截图如下
具体做法(略)
见 大佬的分析;