递归算法是一种极其“优雅”的算法,它将人分为三个截然不同的阵营:恨它的、爱它的以及恨了之后又爱上它的。我则属于第三个阵营。下面将谈谈我 对递归的一些浅显认知。
递归算法的核心分为两部分:基线条件(即结束条件)和递归条件,由于递归函数调用自身,所以很容易出现无限递归的情况,因此弄清楚基线条件非常重要,而且你的基线条件要尽可能地简单。
下面从最简单的递归求阶乘算法说起:fact函数为求阶乘主函数,下面为其递归调用示意图
注意每个fact函数都有自己的x变量,在一个函数调用中不能访问另一个的x变量,但是每次未调用的函数状态会被保存下来,待有一个函数调用被返回时再一层层地按原来的状态依次返回。
再举一个简单的例子:用递归实现数组内数字的求和
其实对于分治法来说,也用到了递归的思想:比如有一块小土地,要求你将其均匀地分成方块,且要求分出的方块尽可能大,应该如何划分。
首先此问题的解决过程包含两个步骤:
1.找出基线条件,这种条件必须尽可能简单。
2.不断将问题分解(或者说缩小规模),直到符合基线条件为止。
下面使用这种方法来解决该问题:
首先找出基线条件。最容易处理的情况是一条边是另一条边的整数倍(可作为基线条件),比如一边长50,另一边长为25,则可直接分成两个方块。
现在需要找出递归条件,每次递归都必须缩小问题的规模,那么如何缩小问题的规模呢?我们可以首先找出这块地可容纳的最大方块如下:
可以划分出两个640*640的方块,同时剩下一小块地,现在是顿悟时刻:剩下的一小块地是否可用同样的算法呢?
很明显这是同一类的问题,因此可以使用同一种方法来解决,所以再次使用同样的方法,对剩下的土地做划分,以此类推,直到满足基线条件:
在此重申一下分治法工作原理:
1.找出简单的基线条件;
2.确定如何缩小问题的规模,使其符合基线条件。
下面附上相应代码:
#include<iostream>
using namespace std;
int F(int w,int h) {
int max, min;
max = w >= h ? w : h;
min = w <= h ? w : h;
if (max%min==0) {
return min;
}
else {
return F(max - min, min);
}
}
int main() {
int w, h;
cout << "依次输入长、宽:";
cin >> w >> h;
cout << endl;
cout << "复合条件的正方形的边长为:";
cout<<F(w, h)<<endl;
system("pause");
}