通过之前的文章函数递归1和函数递归2,让大家了解到了基础的函数递归,这篇文章会通过一些经典的习题让大家熟练使用递归。
就像前面的图片一样函数不停的一层调用下一层,最后返回。需要掌握大事化小的思想,具体如何的实现是需要多个题目来练习的
今天就来做一下比较经典的斐波那契数列
这里我使用了力扣上的习题来做讲解
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。
示例 1:
输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:
输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:
输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
提示:
0 <= n <= 30
那我们先从题目解析开始
光看题目感觉有点让人云里雾里,所以可以举个例子 假设有一个斐波那契数列,该数列为0,1,1,那么之后的每一个都应该为之前两个数之和,所以下个数就应该是1+1也就是2。力扣的题目会在给了你其他的代码,你只需要直接实现这个函数就行了,它会提供多种测试用例来提供给你测试。这道题目是要求提供一个数,然后算出这个数的斐波那契数列各个数之和。
这里还是用刚才那个数列进行假设(1,1,2,3,5)这时力扣的后台就会给你提供5这个数字
此时5就应该等于2+3.划分出来2和3后,2=1+1,3=1+2;到了1之后就不能再向下化小了,但是3后面的2还可以继续化小,化成2=1+1,把所有的1加起来,第五个数字就应该为5
这里可以画一幅图给大家解释一下
这里我再画一个递归的图解为例,帮助大家理解斐波那契数列
这里我们可以再在vs2022上进行测试,可以根据力扣旁边的测试用例来,这里我就只使用一个,当n=3的时候
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
#include<string.h>
int fac(int n);
int main() {
printf("%d", fac(3));
return 0;
}
int fac(int n) {
if (n <= 1) {
return 1;
}
else {
return n + fac(n - 1);
}
}
这样一个简单的递归就完成了。,当然我们要学的不仅仅是这些,这里我把n改为50,再让程序算出第50个数
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
#include<string.h>
int fib(int n);
int main() {
printf("%d", fib(50));
return 0;
}
int fib(int n) {
if (0 == n) {
return 0;
}
if (1 == n) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
大家可以照着代码敲一下,在自己的电脑上运行时,就会发现你等了许久,都没有计算出结果。这是为什么呢????
因为递归进行了大量的重复的计算,如果大家有兴趣,可以在自己的电脑上跑一下这个程序,大概需要5min左右。这里我用图片为大家解释一下原因
这样的图有点像数据结构中的树,当然按照这幅图依次计算,就会耗费大量的时间,直到第一个为1的斐波那契数列。在第一层需要计算2^0,第二行时计算2^1次,这样算到最后就需要2^49次,这样我们计算的效率就会非常低。
这里我也可以写一个代码让大家了解一下递归到底需要的时间
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
#include<string.h>
int count = 0;
int fib(int n);
int main() {
printf("%d\n", fib(20));
printf("%d", count);
return 0;
}
int fib(int n) {
if (0 == n) {
return 0;
}
if (1 == n) {
return 1;
}
if (n == 3) {
count++;
}
return fib(n - 1) + fib(n - 2);
}
这里我定义了一个全局变量count,每当递归到n=3的时候count就+1,最后运行一下可以看看到底需要进行多少次的计算
当我们需要算斐波那契数列的第20个数的时候,fib(3)就被调用了3次
这样的题目我们会发现在计算大的数字的时候,计算机会耗费很多时间,这里我们也可以通过使用循环来计算。
这道题也可以这么想:
斐波那契数列无非就是第3个数就是第一个数+第二个数,第4个数就是第三个数+第二个数
所以经过循环思想的优化。我们也可以这样计算斐波那契数列
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
#include<string.h>
int fib(int n);
int main() {
printf("%d\n", fib(20));
return 0;
}
int fib(int n) {
int a = 1;
int b = 1;
int c = 1;
//斐波那契数列的前两个数为1
while (n >= 2) {
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
但是这里其实包括了一点小技巧,本来斐波那契数列要计算第三个数c大家一般会想到初始化为0.可当n=1的时候,这样返回值就为0了,所以这里将c赋值为1。
到这里,函数的递归就差不多讲完了,剩下的只能靠读者们在不断刷题中灵活运用了,希望在以后的不管是考试还是竞赛都可以灵活使用递归