递归是一个神奇的算法,它是编程书籍中讲解的最尴尬部分 。这些书籍通常会展示一个递归的阶乘实现,然后警告你,虽然它能运行但是它非常的慢并且可能会堆栈溢出而崩溃 。虽然大家对它持怀疑态度,但是这不影响递归是算法中最强大的想法 。
让我们来看看经典的递归阶乘:
factorial.c
文章插图
每次调用factorial都会生成一个新的栈帧 。这些栈帧的创建和销毁使得递归因子比其迭代部分慢 。在调用开始和返回之前的这些栈帧累积是可能耗尽栈空间并使程序崩溃 。
但是这些担忧通常是理论上的 。例如,栈帧 factorial每个占用16个字节(这可以根据栈对齐和其他因素而变化) 。如果您在计算机上运行现代x86 linux内核,通常默认有8兆字节的堆栈空间,因此factorial n最多可以处理512,000 。这是一个巨大数,需要8,971,833位来表示这个数,所以栈空间是我们问题中最少的:一个微弱的整数 - 甚至是64位 - 在我们用完栈空间之前会溢出数万次 。
我们稍后会看一下CPU的使用情况,但是现在让我们从位和字节中退一步,看看递归作为一种通用技术 。我们的阶乘算法归结为将整数N,N-1,... 1推入堆栈,然后以相反的顺序将它们相乘 。我们使用程序的调用堆栈执行此操作的前提是:我们可以在堆上分配堆栈并使用它 。虽然调用堆栈确实具有特殊属性,但它只是您可以使用的另一种数据结构 。
一旦你看到调用堆栈作为一个数据结构,其他东西就变得豁然开朗了:将本身之前所有这些整数累加起来
推荐阅读
- 带你深入了解高并发架构
- Riot.js 框架深入解析
- Lambda 深度递归的尾调用
- 如何理解电子商务法规定的电子商务经营者 电子商务法基本原则
- 二叉树的遍历-递归和非递归
- 甘肃农业大学|怀孕员工夜班打瞌睡被辞,看完不难理解,女性为何会恐育
- 理解茶汤入口有甜味
- 架构师深入剖析JVM体系结构详解
- 让你快速理解风水知识青龙白虎
- 理解软件设计模式