一、递归的应用:汉诺塔
1. 什么是汉诺塔
汉诺塔问题是法国数学家Edouard Lucas于1883年,根据传说提出来的:
传说在一个印度教寺庙里,有3根柱子,其中一根套着64个由小到大的黄金盘片,僧侣们的任务就是要把这一叠黄金盘从一根柱子搬到另一根,但有两个规则:
- 一次只能搬1个盘子
- 大盘子不能叠在小盘子上
神的旨意说一旦这些盘子完成迁移寺庙将会坍塌,世界将会毁灭……
网上有很多汉诺塔的小游戏,大家可以自己搜一下玩一玩。
2. 神的旨意是千真万确的!
虽然这些黄金盘片跟世界末日有着神秘的联系,但我们却不必太担心,据计算,要搬完这64个盘片,需要的移动次数为:
2 64 − 1 = 18 , 446 , 744 , 073 , 709 , 551 , 615 2^{64}-1 = 18,446,744,073,709,551,615 264−1=18,446,744,073,709,551,615次,如果每秒钟搬动一次,则需要584,942,417,355(五千亿)年!
3. 使用递归思想解决汉诺塔问题
递归思想的精髓在于将问题分解为规模更小的相同问题。假设我们现在需要解决5个盘子的汉诺塔问题,可以试着将问题规模缩小:
- 先把最上面的4个盘子移到二号柱子;
- 然后把第5个盘子就直接移动到三号柱子;
- 最后将二号柱子上的盘子借助一号柱子移动到目标柱(依旧是这个思路,只是柱子不同)。
而上面4个盘子的移动我们可以如法炮制,先移动最上面的3个盘子,那么第4个盘子移动到三号柱子上……;直到剩下1个盘子。
基本结束条件,也就是最小规模问题是:1个盘片的移动问题。
4. python代码实现
上面的思路用Python写出来,几乎跟语言描述一样:
def moveTower(height,fromPole, toPole, withPole):
"""
汉诺塔
:param height: 盘子的数量
:param fromPole: 当前的起始柱子
:param toPole: 当前的目标柱子
:param withPole: 当前的中间柱子(或者叫过渡用的柱子)
"""
if height >= 1:
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(height,fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)
def moveDisk(disk, fromPole, toPole):
print(f'盘子{disk}从{fromPole}柱子移动到了{toPole}柱子')