Lec 01 - Resursion 递归
Lec 01 - Resursion 递归
Sarzn递归的概念
递归是一种在计算机科学中非常重要的编程技术(思想), 它可以简化许多的问题
递归函数具体是指函数在定义的时候直接或者间接的调用自身的方式
举一个简单的递归程序 1
2
3
4
5
6
7
8
9
10
using namespace std;
int main()
{
cout << "zz" << endl;
main(); // 在 main 函数的里面又调用了 main 函数, 这就是递归
return 0;
}
(这个例子只是为了展示递归的思想, 不是为了解决真实的问题, 如果实际运行这个代码那么他会陷入死循环)
递归的概念
递归可以把一个大型的复杂的问题, 转化为一个与原问题相似, 但是规模较小的问题来求解. 直到子问题不能再被拆分, 可以直接求解, 递归就结束了. 递归的思考范式就是把大事化小的过程
递归中的递就是递推的意思, 归就是回归的意思, 接下来我们将慢慢体会
!–递归的必要条件–!
在书写递归的时候, 有两个必要条件:
- 退出: 递归存在限制条件, 当满足这个限制条件的时候, 递归💩不再继续
- 渐进: 在递归的过程中, 我们要不断的向着退出条件靠近
接下来我将举出几个例子让你体会体会…
例子1: n 的阶乘(factorial)
https://www.luogu.com.cn/problem/P5739
我们现在想要计算 n 的阶乘, 根据递归的思想, 大事化小… 想要计算 n 的阶乘, 就只要先把 n - 1 的阶乘计算出来, 再乘上 n, 就得到了 n 的阶乘
从 n 的阶乘公式不能看出: 如何把一个较大的问题, 转化为一个与原问题相似, 但是规模较小的问题来求解
n-1 的阶乘和 n 的阶乘是相似的问题, 但是规模较小, 其中有一钟特殊情况是: 当 n == 0的时候, n 的阶乘是 1. 而其余 n 的阶乘都是可以通过上面的公式计算的:
代码实现
1 |
|
(这里不考虑 n 太大的情况, n 太大存在栈溢出)
画图推演
递归与循环
求n的阶乘, 我们很容易就能得到递推公式, 但是这个问题也是可以用循环的方式去解决的.
想要计算 n 的阶乘, 只要能产生从 1~n 的数字, 然后累计相乘就好了
1 | // 使用循环的方式实现 |
说明:
这里简单的对比一下递归和循环的差异: 在C语言中每一次函数调用,都需要为本次函数调用在内存的栈区,申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就一直占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。
所以就当前的问题来看,使用循环来解决更好,效率更高。
我们看到的许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高。当一个问题非常复杂,难以使用迭代的方式实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。
例子 2: 求第 n 个斐波那契数列
https://www.luogu.com.cn/problem/B2064

1 |
|
类似的, 我们会发现, 随着递归的深入, 冗余的计算变得越来越多. 其实对于斐波那契数列的计算使用递归的方式是非常不明智的, 我们可以采用迭代的方式去解决
你可以创建一个足够大的数组, 初始化好前两个元素为 1. 使用一个 for 循环计算, 往后的每一个元素都是前两个元素的和, 然后放到数组里面去. 这样的话进行一次初始化之后, 再进行查询的时间复杂度之间变为O(1)了
再者, 你也可以直接用递归的方式去计算第 n 个斐波那契数的结果, 在下面我给出一种实现方式
1 | // 使用循环实现 |
递归练习
练习1: 求 1+2+3+…+N 的值
https://www.luogu.com.cn/problem/B2142
练习 2: 阿克曼(Ackermann)函数
https://www.luogu.com.cn/problem/B2144
练习 3: digit 函数
https://www.luogu.com.cn/problem/B2145
练习 4: 求 f(x,n)
https://www.luogu.com.cn/problem/B2147
练习 5: 再求 f(x,n)
https://www.luogu.com.cn/problem/B2148
练习 6: 进制转换
https://www.luogu.com.cn/problem/B2143
我的解答
练习1: 求 1+2+3+…+N 的值
1 | // https://www.luogu.com.cn/problem/B2142 |
练习 2: 阿克曼(Ackermann)函数
1 |
|
练习 3: digit 函数
1 |
|
练习 4: 求 f(x,n)
1 |
|
练习 5: 再求 f(x,n)
1 |
|
练习 6: 进制转换
1 |
|





