递归

时间:2022-06-22
本文章向大家介绍递归,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.net/zy010101/article/details/81359290

递归是一种重要的数学思想,我们有时候会见到一个函数是用它本身定义的,这个时候
我们就称它是递归的。现代的大多数语言都是支持递归的。递归有两个重要的问题需要
确定。*首先*你必须要有某些基准情况,基准情况不需要递归就能解决;*其次*递归在
回溯的时候一定能朝着基准方向前进。
    我们来举个例子说明一下递归:  这段代码是用来求阶乘的。当然这里只是举例子
的时候对数值运算使用了递归,通常对于数值计算不要去使用递归。  
#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);
}