python代码用递归函数解决汉诺塔移动步骤的深度详解

        汉诺塔游戏是一个古老的印度游戏。说有A,B,C三根柱子,在A柱上套着64个圆盘,圆盘从下往上依次变小,游戏要求把A柱上的这些圆盘全部移动到C柱,移动过程可以借助B柱暂存圆盘,移动完后在C柱上也是由下到上依次减小。移动过程遵循两个规则——1.一次只能移动一个圆盘;2.不能出现较大盘压住较小盘的情况。

        那么问题来了,这个游戏目标能实现吗?如果能,如何实现?

        我们先讨论第一个问题,能不能实现。为了讨论这个问题,我们先从最简单的情况入手,假如A柱上有2个圆盘(当然,1个更简单,但是讨论2个更有意义),这样如何实现?其实一看就能看出来,总共分三步,第一步先把A柱上边的圆盘移到B柱,第二步再把A柱下边的圆盘移到C柱,第三步再把B柱上的刚才暂时放到这的圆盘移动到C柱,完成。

        如此说来,2个圆盘是没有问题的,我们再进行一下推广,换成3个圆盘,应当如何移动呢?我们仍然分成三步,既然2个圆盘可以移到C柱,那么按照刚才的步骤同样也可以移到B柱,所以,这三步为:第一步:先把A柱上边的2个圆盘移动到B柱,第二步:再把A柱最下边那个圆盘移到C柱,第三步:再把B柱上的2个圆盘移到C柱,完成。

        如此说来,3个圆盘也是可以实现的。既然3个圆盘可以实现,那么按照同样的方法,4个也可以实现,5个、6个......一直到N个都可以实现。所以,64个当然是没问题的。

        那么64个如何实现呢?按照刚才的讨论,我们把思路反过来,总共分三步,第一步:把A柱上边的63个圆盘先移到B柱,第二步:再把A柱最下边的一个圆盘移到C柱,第三步:再把B柱上的63个圆盘移到C柱

        第二步符合规则,但是第一步和第三步不符合,因为一次只能移动1个,怎么办呢?喝口水,别着急,办法总会有的。我们可以把第一步和第三步分别再细化一下,把第一步再分成三步:第一步:把A柱上边的62个圆盘先移到C柱,第二步:再把A柱的第63个圆盘移到B柱,第三步:再把C柱上的62个圆盘移到B柱。如此一来,刚才的第一步就实现了(即把A柱上边的63个圆盘先移到B柱),第二步直接移过去(即把A柱最下边的一个圆盘移到C柱),第三步再细分成三步:第一步:把B柱上边的62个圆盘先移到A柱,第二步:再把B柱的一个圆盘移到C柱,第三步:再把A柱上的62个圆盘移到C柱。如此一来,刚才的第三步也实现了(即再把B柱上的63个圆盘移到C柱)。这样三步下来,任务就完成了。

        慢慢慢,你刚才把第一步和第三步分别又细化成了三步,但是又细化的这三步的第一步和第三步还是不符合规则啊?      瞧我这脑子,差点把这茬给忘了,没关系,如果不符合规则,我们就按照同样的方法再细化成三步,如果再不符合,就再再细化成三步,直到符合规则了,问题就迎刃而解了。

        为了更直观的表达这个思路,请看下图:

 

        方框代表这一步不能直接实现,需要细分,如果细分后能实现了,那么方框这一步也就实现了。而横线代表这一步可以直接实现。

        我们来分析一下这个图,在黑色层面,第一步和第三步不能直接实现,所以把这两步细分到了红色层面,而红色层面的第一步和第三步也不能直接实现,所以又细分到了绿色层面,绿色层面的第一步和第三步也不能直接实现,所以又细分到了蓝色层面,到了蓝色层面,三步都可以直接实现了,于是蓝色层面就都实现了,随着蓝色层面的实现,绿色层面也实现了,随着绿色层面的实现,红色层面也实现了,随着红色层面的实现,整个问题就实现了。

        这个思路就是递归,我们用递归式来解决。代码如下:

 

        为了更好的理解这个代码的实现过程,为了既最简单化又能全面的了解这个过程,我们以4层为例 。我们用缩进来表示递归的深度。

        函数有4个参数,n代表圆盘层数,其它三个分别代表3个柱子。

        我们调用这个函数,把具体的参数传进去,看看函数内部发生了什么。

        当我们调用这个函数后,函数内部代码开始执行,首先进行判断,因为n不等于1,所以if 下的语句不执行,而执行else下的语句,首先执行第5行——调用自己,在调用自己的时候,我们发现有两处变化,一个是层数减少了一层,二是后边的两个参数的位置给互换了一下。这两处变化我们先不用管,当执行完这句调用自己的语句后,接下来又执行了第6行,即打印出了一个移动步骤,当打印完这个移动步骤后,接着又执行第7行,第7行又是调用自己, 在调用自己的时候,参数还是两处变化,这两处变化又有所不同,一是层数仍然是减少了一层,二是这次是前边的两个参数进行的互换。如下图:

        当我们初次调用这个函数时,函数内发生了三步,一是调用了自己,二是打印出了一个步骤,三是又调用了一次自己。 

        我们现在来分析一下这两句调用自己的语句所发生的变化。第一步调用自己,层数由4变成了3,后边两个参数的位置为什么让他互换?我们想象一下前边所说,当是2层圆盘的时候,我们先把A柱上的圆盘放到了B柱,而当是3层圆盘的时候,我们先把A柱上的圆盘放到了C柱,而当是4层圆盘的时候,我们先把A柱上的圆盘又放到了B柱,所以随着层数的变化,B和C也是交替变化的。所以这一步是后边两个参数互换。

        我们再分析一下第三步调用自己,层数由4变成了3,前边两个参数位置为什么互换?我们再想象一下,当是两层圆盘的时候,最后一步是从B移到C,而当是三层圆盘的时候,最后一步是从A移到C,而当是4层圆盘的时候,最后一步又是从B移到C。所以,随着层数的变化,A和B是交替变化的,所以这一步是前边的两个参数互换。

        我们再往下分析,当第一次调用自己时,参数仍不满足n等于1的条件,所以又继续执行else下的语句,即又调用了自己,于是如下图:

 

        步骤同上,在这里就不再赘述。到这一层仍然不满足n等于1的条件,于是再往深一层里递归,如下图: 

        到这一层后,n满足了条件,于是打印出步骤后递归结束,如下图: 

        我们只保留步骤,其他删除,如下图: 

        自上而下,就是完整的移动步骤。 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值