不是每个程序员天生对递归理解深刻,刚入大一时候,当别人写出第一个求最大公约数的递归函数时,对其多么的惊叹,竟然可以不用循环,竟然代码可以这么简洁,确实递归在大多数情况下实现时候代码很短,大部分人也知道递归,也能基本看懂递归,可是却经常不知道怎么写,或者写出来的递归经常死循环,写算法往往也是学的是套路,只有极少数人是创造算法的,大部分人是用算法的,而递归是确实有套路可循的。
本文即从递归的扎马步开始,从几个简单例子到通用套路,一步一步拆解递归
1 递归的三要素
写递归,就是写三要素的实现,三要素分别为函数,边界,递推公式,刚开始只要记住要这么写,写几个算法之后,就能慢慢明白为什么要这样搞。
1.1 递归首要元素-函数
明确你的函数是干什么用的,函数的入参应该是什么,返回值是什么,这三个问题,先从函数是干什么用的开始,你可以定义一个函数f()
假设已经实现了每一步递归的实现,再去明确这个实现 到底做了什么,入参至少要什么,返回值和参数返回可以理解为是一个东西,都是为了返回给上层调用或者全局的一个数据,想清楚函数的三个要素,那你的函数就定义好了。
1.2 递归边界、跳出递归
同样,先这样去做,再去想为什么,这一步要判断的就是函数的入参,入参的null
,入参为初始值,比如斐波那契数列的前1位或者2位,开始时候可能不一定想的完全,那没关系,下面的一步还会继续完善,所以我这里举得例子是斐波那契的前1或2位,而不是直接说结论,这一步骤是在函数的实现里面,所以考虑方式就是假设,入参到了临界值或者初始值,或者特殊值,你要判断一下,第一遍写的时候比如斐波那契,可以直接这么写
if (n == 1)
return 1;
if (n == 2)
return 1;
想到的不一定完全对,或者那么地很优雅, 没关系,只要想到要考虑边界就可以了。下面就是想边界的意义是什么?有两点,其一,异常值边界,其二递归结束判断,比如此题中的n < 0 怎么办,和 n == 1
和 n == 2
就分别对应前面说的,当然这两点可能考虑不那么完全,假设你只考虑了像前面代码中的,或者写边界时候发现写的多了,或者冗余了,这样不影响程序的结果,那么写完递推公式,我们再来回顾边界问题。