前言
本人使用CSDN只是希望将我学习到的东西,记录下来,同时分享给大家,大家一起进步!如本文章有哪些地方有错误,请指正。
一、简单通过定义和一个例子初始递归函数
1.介绍
- 递归就是一个函数在它的函数体内调用它自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。递归函数必须有结束条件。在求f(n)的时候,你就默认f(n -1)已经被求出来了,至于怎么求的,这个是计算机通过回溯求出来的,也就是涉及到栈的存储结构。
- 递归函数有两个要素:(1)边界条件:确定递归到何时终止,也称为递归出口。(2)递归模式:大问题是如何分解为小问题的,也称为递归体。递归函数只有具备了这两个要素,才能在有限次计算后得出结果
2.函数的递归的主要目的
递归函数的主要目的就是“大事化小,小事化了”。递归和二叉树是密切相关的,可以尝试通过二叉树的数据结构来理解递归是如何将一个问题拆分成若干子问题,求解再回溯的,得到最终答案。
3.一个递归函数的例子
我知道官方介绍有点折磨人,那就直接上代码解释吧,思路和代码如下:
例:用递归函数的思想,写出一个n!的代码。(提示:n!= 1 x 2 x 3 x … x n)
思路如下:
(1)例如:5!
(2)n!等于多少的公式就显而易见了
代码如下:
当用户输入小于0的数,就意味着输入的数值有误;当n == 1时就返回1,也就是达到了递归函数的结束要求,结束最后一个函数,也就是最上的一个函数出栈。
#include<stdio.h> int fac(int n) { if (n < 0) { return -1; } else if (n == 1) { return 1; } else { return n * fac(n - 1); } } void main() { int a; scanf("%d", &a); int b = fac(a); if (b == -1) { printf("error"); } else { printf("%d的阶乘为:%d", a, b); } }
运行结果如下:
二、递归函数的缺点(通过斐波拉及数列举例)
例:用递归的思路或循环的思路,敲出第n斐波拉及数的值。(提示:1,1,2,3,5,8 ……,斐波拉及数列就是第n个数是n-1和n-2数的和)
当我们要知道第n个值为多少,就得知道n-1和n-2个数为多少,因为n = (n - 1)+(n - 2),代码如下:
用递归函数求解斐波拉及数列有一个缺点:会计算大量重复的数值,口说无凭,直接上图解!
重复多次计算了第六个斐波拉及数的值,这些都是不必要的运算,所以求解斐波拉及数列不适合使用递归思想求解,可以使用循环求解,代码如下:
三、汉诺塔思路与代码
汉诺塔代码的功能:计算盘子的移动次数,由数学公式知,汉诺塔的盘子移动次数与盘子数n存在这样的关系,移动数 =,后面可以用这个公式来验证我们代码。
汉诺塔的规制:(1)有三根相邻的柱子,标号为A,B,C。(2)A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘。(3)现在把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方。
首先我们知道只能让大盘子在最下面,如果有两个盘子,那么有多上次移动次数呢,直接上图解:
总结:我们想知道n个盘子的次数,记住了,在求解f(n)的时候,我们直接默认f(n - 1)已经完了就可以了!这个在前面已经解释过了,在此不再鳌述。我们将n-1个盘子当作一个整体:这就是类似于分治求解子问题的思想
那么当由3个盘子时,就有公式:f(3,x,y,z) = f(2,x,z,y),x->z,f(2,y,x,z);当有4个盘子时,就有公式:f(4,x,y,z) = f(3,x,z,y),x->z,f(3,y,x,z).从而推出f(n,x,y,z) = f(n,x,z,y),x->z,f(n,y,x,z)!
注意:参数x,y,z只是表示柱子名,没有参加运算!