# 重新认识递归
正确的学习并理解递归,是整个算法体系中最基础,也是最重要的一节。
在程序设计领域,递归是指函数(或方法)直接或间接调用自身的一种操作,如下图所示。
很多同学可能会觉得,递归的做法绝大部分存在于教科书中,而工程中应该摒弃这种写法。至于理由嘛,一是不好理解,人脑并不像电脑那样能够拥有无穷的栈空间,正确的代码并不容易实现出来,或者花在 debug 的时间很长。二是听说递归的运行效率较差,写出来就显得自己不专业。
其实真相与大家认为的不太一致。递归相比于我们日常生活中的逻辑推演来说的确是一个逆向思维,但从解决一个抽象问题的角度来看,递归其实才是最符合人类解题思路的方式。如果用递归的思路来看待问题,我们需要清楚的就不是从哪里开始解决问题,而只需要知道下一步该干什么就行。而这也就是算法书中所说的,自顶向下的方法。
递归仅需抓住两个关键点:输入是什么,以及什么时候停止递归并输出。从而避免了我们仔细的去控制嵌套过程中的各个变量的变化关系。因此,从这个角度来说,递归的写法其实更易于程序员对功能进行了解,而不必深抠细节。同时,由于无需定义中间层变量,代码量也大为精简。
另外说到执行效率低的问题。诚然,对大部分语言来说,递归都是使用的栈机制来实现的,对于嵌套数极多的调用来说,使用递归的方式占用的空间(或内存)会变大,另外,递归会带来额外的函数寻址及调用开销,确实在一定程度上影响运行效率。但对现代程序设计的绝大部分应用场景来说,这点多余的调用对于性能的影响可以说微不足道。
绝大部分递归反对者可能遇到的真实情况是,在使用递归时使用了不恰当的返回时机,或者相比迭代方法,少考虑了可以剪枝的情况,从而导致程序执行了多次无用的操作,导致性能下降。关于这一点就显然是程序设计者自身的水平问题了,递归可不背这个锅。
总而言之,虽然递归的解题方式可能在执行效率上略有影响,但它在抽象问题或者复杂情景下,对解题思路的梳理,以及程序的可读性上都有着极大的帮助,非常适合解决抽象的算法提型。我们在之后的算法专题解析中将会明显的发现这一点。
即使抛开算法不谈,递归思维的养成,对快速了解工程中的复杂场景也是很有帮助的。比如从现在开始,以递归的思维方式,从入口处开始粗读 React 的源码,你会有事半功倍的感觉。
当然,任何问题的解决都没有银弹,递归思维也许不是万能的,但在不了解递归前,消除对递归的偏见,时刻想着还有这么一种简化问题的思维,这对成为计算机人才来说很有必要。