递归算法

2024-04-11

什么是递归?最直观的理解就是函数自己调用自己

如下:

int f(int n){
    return f(n)
}

递归的三大要素

  1. 第一要素:明确你这个函数想要干什么

  2. 第二要素:寻找递归结束条件

  3. 第三要素:找出函数的等价关系式

第一要素:明确你这个函数想要干什么

对于递归,我觉得很重要的一个事就是,这个函数的功能是什么,即这个函数要输入什么,然后输出什么。

例如,我定义了一个函数

复制代码// 算 n 的阶乘(假设n不为0)
int f(int n){
    
}

这个函数的功能是算 n 的阶乘。输入一个整数n,然后输出整数n的阶乘。明确函数要做什么,接下来便是找出递归结束条件。

第二要素:寻找递归结束条件

所谓递归,就是会在函数内部代码中,调用这个函数本身,所以,我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无底洞,导致程序栈溢出。

也就是说,我们需要找出当参数为啥时,递归结束,之后直接把结果返回,请注意,这个时候我们必须能根据这个参数的值,能够直接知道函数的结果是什么。

例如,上面那个例子,当 n = 1 时,那你应该能够直接知道 f(n) 是啥吧?此时,f(1) = 1。完善我们函数内部的代码,把第二要素加进代码里面,如下

复制代码// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n == 1){
        return 1;
    }
}

有人可能会说,当 n = 2 时,那我们可以直接知道 f(n) 等于多少啊,那我可以把 n = 2 作为递归的结束条件吗?

当然可以,只要你觉得参数是什么时,你能够直接知道函数的结果,那么你就可以把这个参数作为结束的条件,所以下面这段代码也是可以的。

复制代码// 算 n 的阶乘(假设n>=2)
int f(int n){
    if(n == 2){
        return 2;
    }
}

注意我代码里面写的注释,假设 n >= 2,因为如果 n = 1时,会被漏掉,当 n <= 2时,f(n) = n,所以为了更加严谨,我们可以写成这样:

复制代码// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
        return n;
    }
}

第三要素:找出函数的等价关系式

第三要素就是,我们要不断缩小参数的范围,以便找到原函数的一个等价关系式。

例如,f(n) 这个范围比较大,我们可以让 f(n) = n * f(n-1)。这样,范围就由 n 变成了 n-1 了,范围变小了,并且为了原函数f(n) 不变,我们需要让 f(n-1) 乘以 n。

说白了,就是要找到原函数的一个等价关系式,f(n) 的等价关系式为 n * f(n-1),即

f(n) = n * f(n-1)。

这个等价关系式的寻找,可以说是最难的一步了

找出了这个等价,继续完善我们的代码,我们把这个等价式写进函数里。如下:

复制代码// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
        return n;
    }
    // 把 f(n) 的等价操作写进去
    return f(n-1) * n;
}

至此,递归三要素已经都写进代码里了,所以这个 f(n) 功能的内部代码我们已经写好了。

这就是递归最重要的三要素,每次做递归的时候,试着去寻找这三个要素。


PREV
递归算法之-斐波那契数列
NEXT
django数据库相关操作