函数递归应用中最经典的案例要算是汉诺塔(Hanoi Tower)问题了。
题目如下:
相传印度有一个梵塔,塔内有三个座A、B、C。A座上有n个盘子,盘子从上到下一个比一个大,最大的在下面。目标:僧人要把这些盘子从A座移到C座,中间借用B座,每次只能移动一个盘子,并且在移动过程中必须始终保持 大盘在小盘的下面。计算不同数量时的移动过程。
分析,既然有第n个盘子,那就有第1个盘子,把盘子从上到下顺序编号为1….n
那么,最底下的第n号盘子就交给方丈了,其他盘子由大师兄全权负责,具体是:
由大师兄负责先把前面n-1个盘子由A移动到B,然后方丈把第n号盘子轻松从A移到C,然后再由大师兄负责把前面n-1个盘子由B移动到C即完成;
那么,大师兄也想了一下,自己就只管第n-1号盘子由A移到B,其他n-2个盘子全交给二师兄去办,具体是:
由二师兄负责先把前面n-2个盘子由A移动到C,然后大师兄轻松把第n-1号盘子从A移到B,然后再由二师兄负责把前面n-2个盘子由C移动到B即完成;
那么,二师兄又想了一下,人家都可以那样干,自己也可以找人啊,于是,每个人都这样想,最后方案简化为每个人都只需做三步:
让别人把其他盘子移到临时座上,自己把最后一个盘子移到自己的目标座,让别人把其他盘子从临时座上移到目标座
这样就形成了递归,每次函数内只做这三件事。
但是递归必须有一个终止条件,终止条件就是最后一个小师弟发现自己就是最后一个了,n=1,那没法再找别人了!自己把盘子乖乖移到目标座吧,没办法了,就相当于本来就只有一个盘子,直接从A移到C,直接返回并结束。
用python代码实现如下:
def hanoi(n, a, b, c):
if n == 1:
print("[%02d]:%s->%s" % (n, a, c))
return
hanoi(n - 1, a, c, b)
print("[%02d]:%s->%s" % (n, a, c))
hanoi(n - 1, b, a, c)
hanoi(3,"a","b","c")
print("done!")
结果如下:
[01]:a->c
[02]:a->b
[01]:c->b
[03]:a->c
[01]:b->a
[02]:b->c
[01]:a->c
done!
加上步数显示,优化代码如下:
cnt = 0
def hanoi(n, a, b, c):
"""
print move info
:param n: the plate number
:param a: the first stick label
:param b: the second stick label
:param c: the third stick label
:return: null
"""
global cnt
if n == 1:
cnt += 1
print("No.%03d [%02d]:%s->%s" % (cnt, n, a, c))
return
hanoi(n - 1, a, c, b)
cnt += 1
print("No.%03d [%02d]:%s->%s" % (cnt, n, a, c))
hanoi(n - 1, b, a, c)
hanoi(3,"a","b","c")
print("done!")
结果如下:
No.001 [01]:a->c
No.002 [02]:a->b
No.003 [01]:c->b
No.004 [03]:a->c
No.005 [01]:b->a
No.006 [02]:b->c
No.007 [01]:a->c
done!