递归为何物?
即是该函数调用它本身自己,这种调用过程称为递归。
递归可以相当于循环,所以想结束递归,就必须有终止递归的条件测试部分,否则就会出现无限递归(即无限循环)。同时,这也是使用递归的难点。
用递归函数调用自己的问题:
1.保存当前指令地址;
2.跳转到被调用函数(指令段)的起始地址实际过程比这个复杂,;
比如还包括保存临时变量和传参等等, 但是对我们正在讨论的问题不起到本质影响所以省略掉不谈函数调用并不是在原地展开代码,每一个函数都是一段独立存在于存储器中的指令序列每个程序的内存空间中都包括一个叫做"栈(stack)"的区域, 它的特点是先进后出, 就像一摞书, 只能往顶端放书, 也只能从顶端取书,每当你调用一次函数, 就会向栈中压入(push)返回地址, 当函数返回(return)时从栈中弹出(pop)返回地址并跳转回返回地址. 所以, 自身调用乃至循环调用形成的递归调用在进行时, 就会不断压栈来保存函数运行状态, 当递归一层一层返回时, 则是不断出栈了。
一般什么时候使用递归?
递归时常用的编程技术,其基本思想就是“自己调用自己”,一个使用递归技术的方法即是直接或间接的调用自身的方法。递归方法实际上体现了“以此类推”、“用同样的步骤重复”这样的思想,它可以用简单的程序来解决某些复杂的计算问题,但是运算量较大。
还有些数据结构如二叉树,结构本身固有递归特性;此外,有一类问题,其本身没有明显的递归结构,但用递归程序求解比其他方法更容易编写程序,如八皇后问题、汉诺塔问题等。
正因为递归程序的普遍性,我们应该学会使用递归来求解问题。直接递归程序与间接递归中都要实现当前层调用下一层时的参数传递,并取得下一层所返回的结果,并向上一层调用返回当前层的结果。至于各层调用中现场的保存与恢复,均由程序自动实现,不需要人工干预。因此,在递归程序的设计中关键是找出调用所需要的参数、返回的结果及递归调用结束的条件。
递归的基本思路:
把一个不能或不好解决的大问题转化为一个或几个小问题,再把这些小问题进一步分解成更小的小问题,
最小问题可以直接解决。
递归的关键在于找出递归的定义和递归的终止条件。
分析问题,寻找递归——设置边界,控制递归——设计函数,确定参数。
递归的例子:
例1:
1 1 2 3 5 8 13 21 ........n
分析可以看出, i 表示第几个数, n表示该数的值
当i = 1 时, n = 1;
当i = 2 时, n = 1;
当i = 3 时 n = i1 +i2;
当i = 4 时 n = i2 +i3
所以可以写个函数
#include<bits/stdc++.h>
using namespace std;
int fun(int n) // 这里的n代表第几个数
{
if(1 == n || 2 == n) // 第一个数
{
return 1;
}
else
{
return fun(n - 1) + fun(n - 2); // 这里就是自己调用自己,形成循环自我调用。
}
}
注: 以上代码只是用来演示递归,不包含错误校验。
在实际生产过程中。该代码不够健壮。
如此,就完成了递归。
例2:
n的阶乘,就是从1开始乘到n,即1*2*3*...*(n-1)*n。
即n!=1*2*3*...*(n-1)*n。
而(n-1)!=1*2*3*...*(n-1)。
所以可以得出,n!=(n-1)! * n。
由这个概念,可以得出递归求阶乘函数fact的算法:
1 如果传入参数为0或1,返回1;
2 对于任意的n,返回n*fact(n-1)。
代码如下:
int fact(int n)
{
if(n == 0 || n == 1) return 1;
return n*(fact(n-1));
}
关于我的想法:
刚接触递归函数的时候,上课听课我就感觉在听天书,课后想了好久也没想明白,问了好多人好不容易想明白,但过后又不懂了,我在百度上也搜了好久,看了好多例题,好不容易现在明白一点点。
在以后的日子里,我会加把劲学习的。