我的学习已经学完了递归函数,但是说实话,刚刚开始听课时,并不能马上就能理解,所以我决定通过自查网上资料自学,以教导的方式去学习递归函数。(其实是要完成作业😭)我的高中老师也说过,教导是学习效率最高的方式。
首先我们要理解函数是什么,我认为,函数是一个接收输入参数-处理功能-输出结果的过程,用大白话讲,就是呼唤,执行,答复的过程。所以调用函数,其实就是发出呼唤,让函数调遣过来使用。而递归,就是把函数运行时调用自己的情况。递归的思想是把一个大型复杂问题层层转化为一个与原问题规模更小的问题,问题被拆解成子问题后,递归调用继续进行,直到子问题无需进一步递归就可以解决的地步为止,举一个我们小时候最简单的故事:从前有座山,山上有座庙,庙里有个和尚......这就是递归的意义。同时,为了避免无限地循环下去,故事不是无限的,所以我们要找一个故事的结局,递归算法就必须要有一个或多个基本情况,这些情况下递归不再进行,而是直接返回一个确定的值,基本情况就是递归的终止条件,它保证递归不会无限进行下去,避免出现死循环。
递归的执行流程如下:当函数被调用时,它首先检查是否满足基本情况。如果满足,则直接返回基本情况对应的值。如果不满足基本情况,函数会通过递推关系调用自身,但是参数传递给自身的函数的规模比原来的问题要小。递归调用将一直进行,直到达到基本情况为止。每一层递归返回一个值,这些返回值会被组合或者处理,最终得到原始问题的解。递归在解决一些问题时具有优雅性和简洁性,但需要小心处理基本情况,以防止陷入无限递归。递归的经典例子包括计算阶乘、斐波那契数列、树的遍历等。 我先讲解一下最经典的例子:计算阶乘。
#include <stdio.h>
int fact(int n)
{
if (n==0) return 1;
return n*fact(n-1);
}
int main()
{ int res=fact(10); printf("%d\n",res);
return 0;
}
首先我们要先定义阶乘的函数,比如5!=5*4*3*2*1,但是递归函数的思想,我们需要把问题分解成更小的子问题,所以5!=5*4!=5*4*3!=5*4*3*2!=5*4*3*2*1!=5*4*3*2*1*0!.又因为0!是一个特殊的值。所以我们吧0!当作一个基本情况,作为终止的条件,所以当这个函数遇到0!时就会返回。随后我们就可以在主函数中调用这个阶乘的递归函数了。还有计算最大公约数的例子也是比较基础的递归函数的用法,就不展开讨论。
我还了解到分治算法常常通过递归来实现。 分治算法的思想就是:分-治-合。分就是把原始问题划分成若干个子问题;治就是将这些子问题直接地求解;合就是将子问题合并,最后解决了母问题。在这个算法中,递归函数扮演着重要的角色。在这个算法中,常用的方法有减而治之(每次让问题减一)和分而治之(每次让问题减半)。
走楼梯是减而治之的经典例子--当有n级台阶,一个人要爬一段楼梯,每次可以迈一步或两步,问有多少种不同的方式爬到楼梯的顶部。当n=1时,只有一种方法;当n=2时,就有两种方法,我们可以走两次一步,或者一次两步;当有n级台阶时,我们每一次走,都要两种选择,走一步或者两步,所以如果我们选走一步,那我们就要n-1后继续选择,走两步同理。然后我们可以得到一个式子:f(n)=f(n-1)+f(n-2),当n>2时。
代码如下:int ways(int n)
{ if (n == 0 || n == 1) return 1;
if(n==2) return 2;else return ways(n - 1) + ways(n - 2); }
分而治之的方法常常用在归并排序中。也很好理解,就是不断缩小范围,使得数字更好地排列,这个思想我们也就不讨论了。 当然,这些都是递归函数最基本的运用,再深入一点,以我目前微薄的水平想要去理解,还需要走很长的路,更不要说去将知识传递出去。但我也从网上了解了很多递归函数的运用:斐波那契数列。
树的遍历: 在树数据结构中递归地进行前序、中序或后序遍历。
拆分问题: 将一个大问题拆分成更小的子问题,分治算法就是典型的递归应用。
图的深度优先搜索: 递归可用于图的深度优先搜索,从一个顶点开始,不断访问邻居节点。
回溯算法: 解决一些组合问题,如八皇后问题或0-1背包问题,通常使用递归进行回溯。
动态规划: 在动态规划中,递归函数可以用于定义子问题和状态转移方程。
字符串处理: 递归可用于字符串处理,例如字符串反转、子集生成等。
机器是笨拙而聪明的,新手程序员们一起加油! (以上资料来自知乎和b站)