递归是一种重要的数学思想,我们有时候会见到一个函数是用它本身定义的,这个时候
我们就称它是递归的。现代的大多数语言都是支持递归的。递归有两个重要的问题需要
确定。*首先*你必须要有某些基准情况,基准情况不需要递归就能解决;*其次*递归在
回溯的时候一定能朝着基准方向前进。
我们来举个例子说明一下递归: 这段代码是用来求阶乘的。当然这里只是举例子
的时候对数值运算使用了递归,通常对于数值计算不要去使用递归。
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int fun(const int a);
int main()
{
int n;
cout << "请输入需要求的阶乘数:";
cin >> n;
cout << "结果是:" << fun(n) << endl;
system("pause");
}
int temp;
int fun(const int a)
{
if (0 == a)
{
return 1;//基准情形
}
else
{
temp = a * fun(a - 1);
cout << "temp is " << temp << endl; //这行是为了打印递归回溯时的中间过程
return temp;
}
}
我们在来看另外一个很著名的问题,汉诺塔问题。这个问题我们也来使用递归求解。
#include <iostream>
using namespace std;
void hanoi(int n, char a, char b, char c);
int main()
{
int n;
cin >> n;
hanoi(n,'A','B','C');
system("pause");
return 0;
}
void hanoi(int n, char a, char b, char c)
{
if (1 == n)
{
cout << a << "->" << c << endl;
}
else
{
hanoi(n - 1, a, c, b);
//hanoi(1, a, b, c);//为了减少调用函数的一点点开销,这里直接使用了输出。
cout << a << "->" << c << endl;
hanoi(n - 1, b, a, c);
return;
}
}
递归主要用于一下三种场合:
1.使用递归代替多重循环,例如8皇后问题,本来需要使用8重循环来解决,现在使用循
环解决,因为n是不确定的。所以我们来用递归写这个程序。代码如下:
#include <iostream>
using namespace std;
void NQueen(int n);
int n;
int QueenPos[100]; //皇后的位置,皇后不能超过100
int main()
{
cout << "请输入皇后个数:";
cin >> n;
NQueen(0); //从第0行开始放皇后
system("pause");
}
//这里使用递归来代替多重循环,N皇后的个数是不确定的,所以必须使用递归来代替多重循环
void NQueen(int k)
{
int i;
if (n == k) //如果k等于n,那么说明n个皇后已经放好了,只需要输出就行了。
{
for (i = 0; i < n; i++)
{
cout << QueenPos[i] + 1 << " ";
}
cout << endl;
return;
}
for (i = 0; i < n; i++)
{
int j;
for (j = 0; j < k; j++)
{
//不能和前k个已经放好的皇后冲突
if (QueenPos[j] == i || abs(QueenPos[j] - i) == abs(k-j))
{
break;//位置冲突,不能放在这儿
}
}
if (j == k) //没有执行break;所以不冲突,放置皇后
{
QueenPos[k] = i;
NQueen(k + 1);//接着去放置下一个皇后
}
}
}
2.使用递归求解本身就是递归的一些事物。例如斐波那契数列从第2项起,有f(n) = f(n - 1)+f(n - 2);
```
int temp;
int Show(const int n)
{
if (1 == n || 2 == n)
{
return 1;
}
temp = Show(n - 2) + Show(n - 1);//这里其实是重复计算了很多次,很不好,这就是前面所说的使用递归来进行数值计算的坏处。
//好处就是看起来清晰明了,很简单。
return temp;
}
```
3.使用递归将问题分解为规模更小的子问题来解决。
爬楼梯,每次可以跨一级台阶,也可以跨两级台阶。求N阶的台阶共有几种走法。
相信大家对于这个问题应该不陌生,这个问题常见于高中数学的排列组合当中。
首先分阶问题,题目要求是N阶台阶的走法,我们来看第一步怎么走,
当N>=2时,第一步有两种走法,走一级或者是走两级。
所以我们分解为了N级走法 = 第一步走一级后,然后走剩下的N-1级 + 第一步走两级
后,然后走剩下的 N - 2阶。到此,我们有了递推公式F(N)= F(N-1) + F(N -2);
(和斐波那契数列一样的公式,但是它们的首项不一样)。我们还缺少基准条件。从分析
中可以看到,我们可以使用 n == 2时,返回2,n == 1时返回1作为基准条件。那么
代码如下:
#include <iostream>
int step(int n);
int main()
{
int n;
std::cin >> n;
std::cout << step(n) << std::endl;
system("pause");
}
int step(int n)
{
if (1 == n)
{
return 1;
}
if (2 == n)
{
return 2;
}
return step(n - 1) + step(n - 2);
}