汉诺塔问题源于印度一个古老传说。相传大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?
在编程语言中,如果一种计算过程的其中每一步都会用到前一步或前几步的结果,这个计算过程就可以称为递归的。而用递归计算过程定义的函数,则被称为递归函数。递归函数应用很广泛,例如连加、连乘及阶乘等问题都可以利用递归思想来解决。而汉诺塔问题也是递归函数的经典应用。
汉诺塔问题的解决思路:如果我们要思考每一步怎么移可能会非常复杂,但是可以将问题简化。我们可以先假设除a
柱最下面的盘子之外,已经成功地将a
柱上面的63个盘子移到了b
柱,这时我们只要再将最下面的盘子由a
柱移动到c
柱即可。
当我们将最大的盘子由a
柱移到c
柱后,b
柱上便是余下的63
个盘子,a
柱为空。因此现在的目标就变成了将这63
个盘子由b
柱移到c
柱。这个问题和原来的问题完全一样,只是由a
柱换为了b
柱,规模由64
变为了63
。因此可以采用相同的方法,先将上面的62
个盘子由b
柱移到a
柱,再将最下面的盘子移到c
柱。
以此内推,再以b
柱为辅助,将a
柱上面的62
个圆盘最上面的61
个圆盘移动到b
柱,并将最后一块圆盘移到c
柱。
我们已经发现规律,我们每次都是以a
或b
中一根柱子为辅助,然后先将除了最下面的圆盘之外的其他圆盘移动到辅助柱子上,再将最底下的圆盘移到c柱子上,不断重复此过程。
这个反复移动圆盘的过程就是递归,例如我们每次想解决n
个圆盘的移动问题,就要先解决(n-1)
个盘子进行同样操作的问题。
有很多人对汉诺塔的解法产生了兴趣。从一阶汉诺塔到N阶汉诺塔它们是否有规律性的算法?
我们在使用程序实现它之前我们来分析分析汉诺塔的解法:
我们设定三个柱子A,B,C。我们的目的是将环从A–>C。当N=1即一阶时它的路径很简单只需要从A->C进行移动。
当N=2时我们需要进行三步:
这里我制作了一个动图来演示了过程。当然N=3时中共7步8帧,由于繁琐的制图我就不继续使用动图演示了!
3阶汉诺塔其实我们都可以轻松的解决。
那么到底他们有什么共性呢?或者说和递归有什么联系呢?
我们还是来使用图片解释:
左图为2阶汉诺塔中间的步骤之一,我们已经将小环移动到了B柱,最大环此时可以视为不存在。那么如右图所示我们将B,C柱子交换位置,那么此步骤是否和移动1阶汉诺塔一样了呢?
然后我们中间执行了将最大环从A移动到C的固定步骤
同理,在左图为2阶汉诺塔中间的步骤之一,我们已经将最大的环移动到了C柱,最大环此时可以视为不存在。那么如右图所示我们将A,B柱子交换位置,那么接下来的步骤是否和移动1阶汉诺塔一样了呢?
到这里我们总结出了如下特点:
其实2阶汉诺塔相当于执行了三大步骤:
1.在ACB的顺序下执行了一阶汉诺塔的移法
2.从A->C移动了最大盘
3.在BAC的顺序下执行了一阶汉诺塔的移法
那么推广到三阶的时候,我们将小环和中环视为一个整体,我们是否又变成了执行二阶汉诺塔方法了呢?
那么四阶前三个环视为整体,五阶前四个环视为整体……我们已经找到了解决汉诺塔方法的递归算法。下面,我们就用代码来实现它。
我们先假设a
柱上只有3
个圆盘,利用Python进行编程实现圆盘的移动,代码如下:
def move(n, a, b, c):
if(n == 1):
print(a,"->",c)
return
move(n-1, a, c, b)
move(1, a, b, c)
move(n-1, b, a, c)
move(3, "a", "b", "c")