关于Python实现汉诺塔问题

发文声明:在刚接触汉诺塔搬盘子这个问题时候,我是很懵的,当时也没多想,后来复习的时候才深入的去剖析了一下,对于我这种小白来讲还是不太容易的,因此我写下这篇博客,来分享一下自己的学习思路心得,希望可以帮助和我一样有困难的小伙伴们。

问题概述:汉诺塔问题,即搬盘子问题,是一个很经典的问题,它的大致内容是:有A、B、C三个区域在平面上横向放置,A称为起始区域,B称为中间区域C称为目标区域,在起始区域有3个盘子,盘子的大小是从下往上依次变小的,即最小的盘子在最上面,最大的在最下面,这样摞在一起的,我们需要做的是将所有盘子一个一个地A起始区域的盘子搬到C目标区域,过程中始终保持大盘子在下,小盘子在上,最我们需要表示出搬运步骤及搬运步数。

问题解答:我做这类问题的方法是递归法。递归法,递归法关注的是基例和链条。基例就是存在一个或多个不需要再次递归的条件,链条就是计算过程中的递归链条,简单理解递归法就是在函数内部调用函数本身。历史上有很多典型的问题都是可以用递归法解决的,例如阶乘问题,n  = n * (n-1)!,基例是当n等于1时值为1;斐波那契数列,F(n)= F(n-1)+ F(n-2),基例是当n等于1和2时值是1,等等等等问题。对于这道题来说,我们用递归法首先应该想到递归链条。假设有3个区域ABC,A起始区域上有n个盘子需要搬到C目标区域上,首先我们将这n个盘子由上到下标号为1、2、3........n号盘子,然后我们可以先将A区域中上面的n-1个盘子借助C目标区域搬到B中间区域,紧接着再把A区域中的第n号盘子,也就是最大的那个盘子放到C区域上,这样我们就完成了第一步。(PS:我们不需要考虑如何将n-1个盘子搬到B区域的操作是如何完成的)紧接着我们将B区域剩余的n-1个盘子借助A起始区域搬到C目标区域上,这就完成了搬运任务。我们需要将每一步的搬运步骤打印出来,并统计搬运步数。下面附上Pyhton实现代码:

#汉诺塔搬盘子问题
count = 0
def hanoi(n,src,dst,mid):  # src→起始区域  dst→目标区域  n→起始区域有n个盘子  
    global count
    if n == 1:
        print("将{}号盘子:{}->{}".format(1,src,dst)) #只有一个盘子直接放到目标区域
        count += 1
    else:
        hanoi(n-1,src,mid,dst) #将上面n-1个盘子借助目标区域搬到中间区域上

        print("将{}号盘子:{}->{}".format(n,src,dst)) #这里的n表示n号盘子
                                                     #把第n号盘子搬到目标区域上
        count += 1  #步骤+1
        hanoi(n-1,mid,dst,src) #将中间柱子上的n-1盘子借助起始区域搬到目标区域

#print函数所完成是把一个盘子从起始区域搬到目标区域的操作
#不关注具体操作,只关注链条(基链)

下面举一个简单的例子:有三个区域ABC,A起始区域上放有3个盘子从上到下标号为1、2、3号盘子,大小由小到大。

大概长这样      ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

首先我们调用函数

hanoi(3,"A","C","B")

print("一共需要",count,"步")

函数内部语句块中文解释流程:在函数<1>hanoi(3,A,C,B)(这里ABC不加引号,偷个懒),第一个参数是3,进入函数内部执行else语句块的第一行,调用函数<2>hanoi(2,A,B,C),语句意思是将A区域上的1、2号盘子借助C区域搬到B区域上,该函数参数为2,继续进入函数内部执行else语句块中的第一行调用函数hanoi(1,A,C,B),语句意思是将A区域上的1号盘子借助B区域搬到C区域上,该步函数参数为1,直接执行if语句块内容,打印(将1号盘子:A→C)。紧接着执行<2>函数的else语句块中的第二行format(2,A,B)),打印(将2号盘子:A→B,然后执行<2>函数else语句块的第四行,调用函数hanoi(1,C,B,A)直接打印(将1号盘子:C→B至此,调用的<2>函数执行完毕紧接着执行<1>函数else语句块的第二行内容(format(3,A,C)),打印(将3号盘子:A→C至此,已经将最大的3号盘子放到了目标区域上。然后执行<1>函数else语句块中第四行(函数的最终步骤),调用函数<3>hanoi(2,B,C,A),语句的意思是将B区域上的1、2号盘子借助A区域搬到C区域上(做完这步即结束任务),继续进入<3>函数内部,参数为2,执行else语句块第一行,调用函数hanoi(1,B,A,C),直接打印(将1号盘子:B→A,再执行else语句块第二行format(2,B,C),打印(将2号盘子:B→C),最后执行else语句块的第四行,调用函数hanoi(1,A,C,A),打印(将1号盘子:A→C),至此结束整个函数调用

输出结果如下:

谢谢大家阅读此篇文章,希望对您的学习有帮助!

  • 17
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王业强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值