前言
先来看两个有趣的故事
- 从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,故事讲的是从前有座山,山上有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,故事讲的是从前有座山,山上有座庙。。。
-
- 问:GNU全称是什么?
- 答:GNU is Not UNIX
- 问:第一个单词GNU的全称是什么?
- 答:GNU is Not UNIX
- 问:第一个单词GNU的全称是什么?
- 答:GNU is Not UNIX
- 。。。
类似于上述这种使用自己来定义自己的结构,称之为递归。
递归思想很有意思,在很多方面都有实际的用途。在计算机编程中,对于一些特定的问题,常规方法往往会显得很繁琐,抓不住问题的本质,这种时候采用递归的思想编程,往往能够写出很优雅的代码。
汉诺塔问题
“汉诺塔”是由数学家爱德华 · 卢卡斯于1883年发明的游戏,爱德华当初用了一个神话来描述这个问题
传说越南河内某间寺院有三根银棒,上串 64 个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。
—— 维基百科
这个问题被数学抽象描述就是
- 问题:有3根细柱子(A、B、C),其中A柱子上有64个圆盘,64个圆盘按照从上到下由小到大的次序排列。求一共需要移动多少次才能将A柱子上的64个圆盘全部移动到B柱子上?
- 移动规则(移动前、移动中、移动后,都必须遵循)
- 一次只能移动柱子最上端的一个圆盘
- 小圆盘上面不能放大圆盘
对于64个圆盘问题,太复杂太庞大了。可以先从最小的情况开始考虑
一层汉诺塔
算法图解如下
规律:
- 将1个圆盘,从A柱子移动到B柱子
记作: A→B A → B
两层汉诺塔
算法图解如下
规律:
- 将2-1个圆盘,从A柱子移动到C柱子
- 将第2个圆盘,从A柱子移动到B柱子
- 将2-1个圆盘,从C柱子移动到B柱子
记作:
- A→C A → C
- A→B A → B
- C→B C → B
三层汉诺塔
算法图解如下
规律
- 将3-1个圆盘,从A柱子移动到C柱子(第1次~第3次)
- 将第3个圆盘,从A柱子移动到B柱子(第4次)
- 将3-1个圆盘,从C柱子移动到B柱子(第5次~第7次)
记作:
- A→B,A→C,B→C A → B , A → C , B → C
- A→B A → B
- C→A,C→B,A→B C → A , C → B , A → B
规律一
由于第四层汉诺塔整个算法图解过程已经很长了,所以这里就不列举了。不过,从前面三层汉诺塔图解算法中,我们足以发现了n层汉诺塔移动的一般性规律
- 将n-1个圆盘,从A柱子移动到C柱子
- 将第n个圆盘,从A柱子移动到B柱子
- 将n-1个圆盘,从C柱子移动到B柱子
我们将上述三个步骤,调换一下顺序
- 将n-1个圆盘,从A柱子移动到C柱子
- 将n-1个圆盘,从C柱子移动到B柱子
- 将第n个圆盘,从A柱子移动到B柱子
调换顺序之后的发现,其实第一步和第二步合起来,便是将n-1个圆盘从A柱子移动到B柱子上 。
因此,算法可以进一步简化为
- 将n-1个圆盘,从A柱子移动到B柱子
- 将第n个圆盘,从A柱子移动到B柱子
将n-1个圆盘从A移动到B的过程,就是将n-2个圆盘从A移动到B,与将第n-1个圆盘从A移动到B;将n-2个圆盘从A移动到B的过程,就是将n-3个圆盘从A移动到B,与将第n-2个圆盘从A移动到B;……;将1个圆盘从A移动到B的过程,就是将第1-1个圆盘从A移动到B,与将第1个圆盘从A移动到B。
很明显,这样的一个过程,就是递归。在整个递归过程中,无论从第几层开始,最后会终止于一个确定的步骤——将1个圆盘从A移动到B,而每一层最关键的一个确定步骤就是——将第n个圆盘从A移动到B。因此整个递归过程其实都是在做一件事情——将1个圆盘从A移动到B !
规律二
由规律一,我们可以得知,整个递归过程中都是在重复做一件事情——将1个圆盘从A移动到B。但事实上,一旦圆盘数目超过1个时,就需要一个借助3根柱子中的一根作为中转站,通过折中的方法实现将圆盘从A的移动到B。
- 将n-1个圆盘,从A柱子移动到C柱子
- 将第n个圆盘,从A柱子移动到B柱子
- 将n-1个圆盘,从C柱子移动到B柱子
由上述总结规律可知,这样的一个过程,起到中转站的作用的柱子似乎就是C柱子。
但是事实上绝不是这样,很多情况下,起到中转站作用的柱子不是绝对的!
分析一个最具代表的模型,三层汉诺塔的表达式
- A→B,