自我介绍:
🏃♂️作者:killer_Li_yy
😁作者的Gitee: killer / killer_li code warehouse
大家好!我是一名软件工程专业的大一学生,希望能在CSDN社区上记录自己的学习,和社区的小伙伴共同进步🎢,如果你有任何想法和建议想同我交流的话,我会感到莫大的开心与荣幸!
✨小提示:在文章中我将用不同颜色的字体来划分不同的内容,一方面便于读者区分,另一方面也是想让自己的文章多些色彩,使文章不那么单调乏味✨
目录
什么是递归?
简单地说,就是如果在函数中存在着调用函数本身的情况,这种现象就叫递归。
是一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
递归的主要思考方式在于:把大事化小
以阶乘函数为例,在 factorial函数中 存在着factorial(n - 1) 函数的调用,所以该函数为递归函数。
咱先来看看阶乘函数的数学公式表达
我们写出它的代码对照着来看
int fac(int n)
{
if (n > 1)
{
return n * Fuc(n - 1); //数学公式
}
else
{
return 1;
}
}
int main()
{
int num = 0;
scanf("%d", &num);
int ret = fac(num);
printf("%d\n", ret);
return 0;
}
相信不少同学和我一样,看到代码后的感觉就是“这不就是照着上面的数学公式敲就行了嘛?”
那咱们进一步剖析「递归」,先有「递」再有「归」,「递」的意思是将原问题拆分成与原问题相似但规模较小的子问题来解决, 子问题再拆解成子子问题,...,直到被拆解的子问题无需再拆分成更细的子问题(即可以求解),「归」是说最小的子问题解决了,那么它的上一层子问题也就解决了,上一层的子问题解决了,上上层子问题自然也就解决了,....,直到最开始的问题解决,文字说可能有点抽象,那我们就以阶层 f(6) 为例来看下它的「递」和「归」。
求解问题 f(6), 由于 f(6) = n * f(5), 所以 f(6) 需要拆解成 f(5) 子问题进行求解,同理 f(5) = n * f(4) ,也需要进一步拆分,... ,直到 f(1), 这是「递」,f(1) 解决了,由于 f(2) = 2 f(1) = 2 也解决了,.... f(n)到最后也解决了,这是「归」,所以明白了嘛?递归的本质递归的本质就是前面提到的那句话“将原问题拆分成与原问题相似但规模较小的子问题来解决直到最后被拆解的子问题再也不能拆分,解决了最小粒度可求解的子问题后,在「归」的过程中自然顺其自然地解决了最开始的问题。”
常见例子:
斐波那契数列(兔子数列)
求第n个斐波那契数。
1、1、2、3、5、8、13、21、34、55...... 从第3项开始每一项等于前两项之和
利用上面介绍的的,我们看看这道题该怎么解
思路:大事化小,找出原问题和与原问题相似但规模较小的子问题。
第一步:用递推公式表示该关系
第二步:用代码来实现该递推公式
int fib(int n) //根据递推公式来写代码
{
if (n <= 2)
{
return 1;
}
else
{
return fib(n - 1) + fib(n - 2);
}
}
int main()
{
int num = 0;
scanf("%d", &num);
int ret = fib(num);
printf("%d\n", ret);
return 0;
}
经过上面两个例子,我们可以总结出一些经验:
1.递归的过程中必须存在限制条件,当达到这个限制条件之后递归便不再继续。
阶乘中的限制条件是当【递】到f(1)时返回值是1,且不再往后继续递归。
斐波那契数列中的限制条件则是当fib(n)中的n为1或2是返回值都是1,且不再递归。
2.在每次递归调用之后必须越来越接近这个限制条件。(上面引用的图表示的非常直观)
青蛙跳台阶
一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。
我们继续沿用刚刚的思路,看看怎么写。
这题乍一看,并不是那么直接就能想到它的递推公式。但相信大家的高中数学老师一定说过枚举法yyds!我们将台阶书设为n。n=1时,有1种方法。n=2时,有2种方法。n=3时,有3种方法。n=4时,有5种方法。n=5时有8种方法......假如你这时已经发现了规律的话,我们便能把它的递推公式写出来了
第一步:写出递推公式。
第二步:用代码来实现该递推公式
int f(int n) //根据递推公式来写代码
{
if (n == 1)
{
return 1;
}
else if (n == 2)
{
return 2;
}
else if (n > 2)
{
return f(n - 1) + f(n - 2);
}
}
int main()
{
int num = 0;
scanf("%d", &num);
int ret = f(num);
printf("%d\n", ret);
return 0;
}
可以观察到,青蛙跳台阶问题其实和兔子繁殖问题其实是非常类似,但为什么在看完兔子问题后再看青蛙会有脑子一抽的感觉呢?
这是因为这两个问题思考的方向不同,兔子繁殖问题是自下而上顺着推的,而青蛙跳台阶问题恰恰相反,自上而下的思考,如果青蛙要跳到第n阶台阶2,那么青蛙就只能从第(n-1)和第(n-2)级阶梯跳。这么一想思路是不是通畅多了?
结语:
作者是第一次尝试写这种文章🧗♂️,如有疏漏,请予斧正,如果这篇文章能够给同我一样正在学习编程的新手小伙伴带来一点点帮助的话,我会感到很开心并且备受鼓励😉!希望我们能在学习编程这条路上相互扶持,走的更远!🙌🙌🙌
(后面将持续对该内容进行补充)