https://blog.csdn.net/wangxiaobupt/article/details/44198949
概念
递归就是某个函数直接或间接调用自身的问题求解过程。
通过将自身问题划分成相同性质的子问题的求解过程,这些小问题的求解过程较容易,小问题的解就构成了原问题的解。
递归算法就是一个函数通过不断对自己的调用而求得最终结果的一种思维巧妙但是开销很大的算法。
步骤
1.理解题意,待求问题的解F(X)
2.通过寻找函数G(),使得F(X)=G(F(X-1)) (原解可以用一些子问题的解来表示,寻找递推关系式)
3.且已知F(0)的值,就可以通过F(0)和G()来求F(X)的解
要点
1.如何将原问题划分成子问题
2.递归终止的条件,最小子问题的求解,允许有多个出口
3.界函数,它保证递归的规模向出口靠拢
关键
1.找出递推关系式
2.找到递归终止条件
注:深层次的递归可能导致栈溢出,可以考虑使用全局数组或动态分配数组
经典的递归问题
- 汉诺塔问题
- 斐波那契数列问题
- 阶乘问题
阶乘例子:
递推关系式 f(x)=x*f(x-1)
终止条件 乘到1后,x-1=0,结束递归返回1
#include <iostream>
using namespace std;
int f(int x)
{
if (x==0)
return 1;
else
return x*f(x-1);
}
int main()
{
int n;
cin>>n;
int count=f(n);
cout<<count<<endl;
}
汉诺塔问题:
首先:对于递归这一类函数,你不要纠结于他是干什么的,只要知道他的一个模糊功能是什么就行,等于把他想象成一个能实现某项功能的黑盒子,而不去管它的内部操作先,好,我们来看下汉诺塔是怎么样解决的
首先按我上面说的把递归函数想象成某个功能的黑盒子,void hanoi(int n,char one,char two,char three); 这个递归函数的功能是:能将n个由小到大放置的小长方形从one 位置,经过two位置 移动到three位置。那么你的主程序要解决的问题是要将m个的”汉诺块”由A借助B移动到C,根据我们上面说的汉诺塔的功能,我相信傻子也知道在主函数中写道:hanoi(m,A,B,C)就能实现将m个块由A借助B码放到C,对吧?所以,mian函数里面有hanoi(m,’A’,’C’,’B’);这个调用。
接下来我们看看要实现hannoi的这个功能,hannoi函数应该干些什么?
在hannoi函数里有这么三行
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
同样以黑盒子的思想看待他,要想把n个块由A经过B搬到C去,是不是可以分为上面三步呢?
这三部是:第一步将除了最后最长的那一块以外的n-1块由one位置经由three搬到two 也就是从A由C搬到B 然后把最下面最长那一块用move函数把他从A直接搬到C 完事后 第三步再次将刚刚的n-1块借助hannoi函数的功能从B由A搬回到C 这样的三步实习了n块由A经过B到C这样一个功能,同样你不用纠结于hanoi函数到底如何实现这个功能的,只要知道他有这么一个神奇的功能就行
最后:递归都有收尾的时候对吧,收尾就是当只有一块的时候汉诺塔怎么个玩法呢?很简单吧,直接把那一块有Amove到C我们就完成了,所以hanoni这个函数最后还要加上 if(n==1)move(one,three);
(当只有一块时,直接有Amove到C位置就行)这么一个条件就能实现hanoin函数n>=1时将n个块由A经由B搬到C的完整功能了。
递归这个复杂的思想就是这样简单解决的,呵呵 不知道你看懂没?纯手打,希望能帮你理解递归
总结起来就是不要管递归的具体实现细节步骤,只要知道他的功能是什么,然后利用他自己的功能通过调用他自己去解决自己的功能,最后加上一个极限情况的条件即可,比如上面说的1个的情况。
//汉诺塔问题
public static void hanoi(int n){
if(n>0){
func(n,"left","mid","right");
}
}
private static void func(int n, String from, String mid,String to) {
if(n==1){
System.out.println("move from "+from+" to "+to);
}else{
func(n-1,from,to,mid);//第一步:1-i从left移动到mid
func(1,from,mid,to);//第二步:i从left移到right
func(n-1,mid,from,to);//第三步:1-i从mid移到right
}
}