递归算法思想
递归也是一种很常见的算法思想,使用该算法可以很有效的解决一些问题,往往可以简化代码的编写,提高可读性。但是如果有不适合的递归,反而会适得其反。
算法思路:
所谓递归,就是程序中不断反复的调用自身来解决问题的方法。这里强调的重点是调用自身,就是要求解的问题能够被分解成多个相同的小问题这样通过多次递归调用,自己便可以完成求解。
递归算法的具体实现过程一般通过函数来完成。在函数的内部,编写程序时,直接或者间接的调用函数自己,即可完成递归操作。这种函数也可以叫做递归函数。在递归函数中,主调函数同时也时被调函数。执行递归函数将反复的调用自身,每调用一次就进入新的一层。
编程经验:
把要求解的问题转化为规模小的同类型的多个子问题,然后递归调用函数,
来表示问题的解,通过多次递归调用,最终可以求出最小问题的解,然后
通过这个最小问题的解,返回上层调用,再求出次小问题的解,再返回上
层,不断重复,最后得到整个问题的解,完成递归调用。
从递归算法的实质可以看出,递归调用其实也是一种循环,只是它不是通过循环语句来实现的,而是通过循环调用函数自身来实现的。要完成整个循环,要满足三个要求:
- 每次循环调用一次,求解问题的规模都要有所缩小,即求解的问题化为一个缩小了的子问题。
- 相邻两次循环之间有紧密的联系,前一次要为后一次做准备,(通常前一次的输出要作为后一次的输入)
- 当子问题的规模极小时,应该能直接给出解答,而不再进行递归调用(即必须有一个循环出口),因此,每一次的递归调用都有条件,无条件的递归调用将会使程序进入死循环,不能正常结束,(最终导致栈溢出)
解决问题时,需要注意一下几点:
- 再使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
- 递归算法通常显得很简洁,但是递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
- 再递归调用的过程中,系统将每一次递归调用的返回点、局部变量等保存再系统的栈中,当递归调用的次数太多时,就可能造成栈溢出的错误。
实例:求阶乘
理解递归算法最简单的例子。
输入一个数n,求出n!。
#include <iostream>
#include <cstdio>
#include <conio.h>
using namespace std;
int fact(int n);
int main()
{
int n;
cin>>n;
cout<<fact(n);
getch();
return 0;
}
int fact (int n)
{
if(n<=1)
return 1;
else return n*fact(n-1);
}
实例:进制转换
#include <iostream>
using namespace std;
void change(int n,int b)
{
if(n>0)
{
change(n/b,b);//递归
cout<<n%b;
}
else
return;
}
int main()
{
int n,m;
cin>>n>>m;
change(n,m); //调用函数
return 0;
}