递归

2019-05-25 19:57:23 浏览数 (1)

版权声明:本文为博主原创文章,转载请注明博客地址: https://cloud.tencent.com/developer/article/1433364

代码语言:javascript复制
递归是一种重要的数学思想,我们有时候会见到一个函数是用它本身定义的,这个时候
我们就称它是递归的。现代的大多数语言都是支持递归的。递归有两个重要的问题需要
确定。*首先*你必须要有某些基准情况,基准情况不需要递归就能解决;*其次*递归在
回溯的时候一定能朝着基准方向前进。
    我们来举个例子说明一下递归:  这段代码是用来求阶乘的。当然这里只是举例子
的时候对数值运算使用了递归,通常对于数值计算不要去使用递归。  
代码语言:javascript复制
#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;
    }
}
代码语言:javascript复制
我们在来看另外一个很著名的问题,汉诺塔问题。这个问题我们也来使用递归求解。
代码语言:javascript复制
#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;
    }
}
代码语言:javascript复制
递归主要用于一下三种场合:
1.使用递归代替多重循环,例如8皇后问题,本来需要使用8重循环来解决,现在使用循
环解决,因为n是不确定的。所以我们来用递归写这个程序。代码如下:
代码语言:javascript复制
#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);//接着去放置下一个皇后
        }
    }
}
代码语言:javascript复制
2.使用递归求解本身就是递归的一些事物。例如斐波那契数列从第2项起,有f(n) = f(n - 1) f(n - 2);

int temp;

int Show(const int n)

{

代码语言:txt复制
if (1 == n || 2 == n)
代码语言:txt复制
{
代码语言:txt复制
    return 1;
代码语言:txt复制
}
代码语言:txt复制
temp = Show(n - 2)   Show(n - 1);//这里其实是重复计算了很多次,很不好,这就是前面所说的使用递归来进行数值计算的坏处。
代码语言:txt复制
//好处就是看起来清晰明了,很简单。
代码语言:txt复制
return temp;

}

代码语言:txt复制
3.使用递归将问题分解为规模更小的子问题来解决。
爬楼梯,每次可以跨一级台阶,也可以跨两级台阶。求N阶的台阶共有几种走法。
相信大家对于这个问题应该不陌生,这个问题常见于高中数学的排列组合当中。
首先分阶问题,题目要求是N阶台阶的走法,我们来看第一步怎么走,
当N>=2时,第一步有两种走法,走一级或者是走两级。
所以我们分解为了N级走法 = 第一步走一级后,然后走剩下的N-1级   第一步走两级
后,然后走剩下的 N - 2阶。到此,我们有了递推公式F(N)= F(N-1)   F(N -2);
(和斐波那契数列一样的公式,但是它们的首项不一样)。我们还缺少基准条件。从分析
中可以看到,我们可以使用 n == 2时,返回2,n == 1时返回1作为基准条件。那么
代码如下:
代码语言:javascript复制
#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);
}

0 人点赞