我开始学递归的时候,头都是大的。
看了一堆网上的教程,什么“递推”“回归”“调用自己”,每个字都认识,连在一起就是不明白。直到有一天,我决定自己动手写代码。我发现了一个好玩的东西——画分形树。
这东西不需要多少数学底子。你只需要知道一个函数能调用自己,就行了。我用的是Python的turtle库,就是那个小乌龟画图。
先画一棵最简单的树,树干向上画一段,然后分两个叉,每个叉再分叉。这就是递归。你让函数画一段树枝,然后左右各转一个角度,再调用自己画更短一点的树枝。要注意的是,你得告诉它什么时候停下来。不然它会一直分叉下去,电脑就卡死了。
我第一天写的代码是这样的:
def draw_tree(branch_len):
if branch_len < 5:
return
t.forward(branch_len)
t.left(30)
draw_tree(branch_len 0.7)
t.right(60)
draw_tree(branch_len 0.7)
t.left(30)
t.backward(branch_len)
运行的时候,我盯着屏幕。小乌龟爬着爬着,一棵树就在我眼前长了出来。那种感觉挺奇妙的。你只写了十几行代码,但出来的东西很复杂,枝枝叉叉的,像真树一样。
递归最难的地方,就是你要相信它能自己结束。你脑袋里不要去想它怎么一层层回来的。你只需要知道,每次调用的时候,参数在变小,到了某个值就停了。就像爬楼梯,你只盯着眼前的一级,不要回头看。让程序自己跑,它就帮你把活干了。
我试着改参数。树枝长度从0.7改成0.6,树就变得稀疏了。改成0.8,树就密得像灌木。角度从30度改成45度,树就张牙舞爪的。你改一个数字,整棵树的样子就变了。这种掌控感,让你觉得递归不再可怕。
后来我在网上看到有人用递归画雪花,画山脉,画闪电。每种东西都长得不一样,但核心思路一样。就是一件事重复做,每次做一点点变化。递归就是这个道理,大事化小,小事化了。
我一个朋友学递归,怎么也学不会。我让他先放下理论,直接打开电脑,把画树的代码敲进去。他敲了一遍,跑起来,看到树长出来,突然就懂了。他说:“原来递归就是套娃啊,大套娃里面有小套娃,一直套到最小的那个为止。”
对,就是这么回事。你别把它想得太复杂。递出去,归回来,中间的部分电脑帮你算好了。你只要把停止的条件写对,把每次变化的量写对,剩下的交给机器。
我有时候觉得递归像人生。你做一个决定,这个决定又导致下一个决定,每个决定都跟前一个有点像,但又不同。直到某个条件触发,整个链条结束。你回头一看,发现原来自己走了这么远。
编程最难的地方,不是语法,不是算法,是你敢不敢放手。你敢不敢让函数自己调用自己,而不去管它怎么工作的。这是一种信任,你信任代码的运行机制,信任你自己写的逻辑。
如果你现在还在被递归折磨,听我的,别看书了。打开Python,装个turtle,从一棵树开始画。画出来你就懂了。没画出来也别急,慢慢调参数,慢慢看错误信息。每调一次,你就多理解一点。
别怕出错,错了就改,改了接着跑。玩着玩着,你就真懂了。