汉诺塔的递归算法
一、 起源
传说越南河内某间寺院有三根银棒,上串 64 个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。但不知道是卢卡斯自创的这个传说,还是他受他人启发。
二、 移动规则
1.每次只能移动一个盘子;
2.大盘不能放在小盘上面;
3.在三根柱子之间一次只能移动一个盘子。
三、 问题抽象
我们要利用抽象思维去思考汉诺塔这个问题,把 A 柱上的盘子看成两份,就是上面的盘子(可能是一个或者多个)和最底下的盘子,不需要关心上面的盘子到底有几个,每次操作就是把最底下的盘子通过缓冲区 B 柱移动到 C 柱。
举例:从左到右有 A、B、C 三根柱子,其中 A 柱子上面有从小叠到大的 n 个圆盘,现要求将 A 柱子上的圆盘移到 C 柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。
-
n == 1 ( sum = 1 次 )
- 第1次 1号盘 A ----> C
- 第1次 1号盘 A ----> C
-
n == 2 ( sum = 3 次 )
- 第1次 1号盘 A ----> B
- 第2次 2号盘 A ----> C
- 第3次 1号盘 B ----> C
-
n == 3 ( sum = 7 次 )
- 第1次 1号盘 A ----> C
- 第2次 2号盘 A ----> B
- 第3次 1号盘 C ----> B
- 第4次 3号盘 A ----> C
- 第5次 1号盘 B ----> A
- 第6次 2号盘 B ----> C
- 第7次 1号盘 A ----> C
规律如下:
1个圆盘的次数 2的1次方减1
2个圆盘的次数 2的2次方减1
3个圆盘的次数 2的3次方减1
…………………………
n个圆盘移动次数为:2^n - 1
四、 算法分析(递归算法)
到目前为止,求解汉诺塔问题最简单的算法还是通过递归方式,递归简单而言就是某个方法或函数,但是在这个函数里有调用自己这个函数的语句,在调用到某一次后函数能返回一个确定的值,接着倒数第二个就能返回一个确定的值,一直到第一次调用的这个函数能返回一个确定的值,也就是最初需要有一个确定的值作为递归结束的条件。
实现这个算法可以简单分为三个步骤:
1. 把n-1个盘子由 A 移到 B;
2. 把第n个盘子由 A 移到 C;
3. 把n-1个盘子由 B 移到 C;
五、 代码实现
1 | def hanoi(n, a, b, c): |
1 | hanoi(3, 'A', 'B', 'C') |
输出结果:
1 | Move disk 1 from A to C |
代码中的移动流程解释
1 | /** |
六、 总结
在学习 python 的时候看到这个汉诺塔问题,被其简洁优雅的代码所震撼,利用递归的方式简单的解决,也让我有了更深入了解算法魅力的想法,感觉算法本质上是在利用数学抽象的方法解决问题,问题就像山顶的旗帜,不同的算法通过不同的路径爬山,有的快有的慢(时间复杂度),有的简单有的复杂(空间复杂度),但是都能到达山顶,这就是算法的魅力所在。