【问题标题】:Towers of Hanoi Python - understanding recursion [duplicate]河内 Python 之塔 - 理解递归 [重复]
【发布时间】:2014-05-31 05:13:39
【问题描述】:

我对 Python 完全陌生,目前正在阅读有关河内塔和递归的教程。我以为我理解了递归,直到他们给出了这个例子:

def moveTower(height,fromPole, toPole, withPole):
    if height >= 1:
        moveTower(height-1,fromPole,withPole,toPole)
        moveDisk(fromPole,toPole)
        moveTower(height-1,withPole,toPole,fromPole)
    #print(withPole)

def moveDisk(fp,tp):
    print("moving disk from",fp,"to",tp)


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

用 3 个圆盘打印解决河内塔问题的正确动作: 将磁盘从 A 移动到 B 将磁盘从 A 移动到 C 将磁盘从 B 移动到 C 将磁盘从 A 移动到 B 将磁盘从 C 移动到 A 将磁盘从 C 移动到 B 将磁盘从 A 移动到 B

我的问题是,它是如何做到的?!有人可以检查代码行,以便我了解它如何打印正确的动作吗?我主要对fptp 的值如何从A 更改为BC 感到困惑。对不起,如果这是一个广泛的问题!任何帮助将不胜感激!

【问题讨论】:

  • 也许这个答案有帮助:stackoverflow.com/a/1223334/3440545
  • 我建议在顶部粘贴print(height, fromPole, toPole, withPole) 看看会发生什么!
  • 非常感谢所有回答的人!现在对我的理解更有信心了:)

标签: python algorithm recursion towers-of-hanoi


【解决方案1】:

该主题已涵盖here,但是如果不熟悉该概念,递归方法可能会令人困惑。该算法首先通过缓存挂钩递归地移动除最后一个磁盘(一个较小的问题实例)之外的所有磁盘,然后“实际上”将最后一个磁盘移动到目标挂钩,然后将塔移动到初始挂钩。实际上,依靠递归,底部的磁盘被移动到目标挂钩,这是不可能直接执行的,因为它是无效的移动。在递归调用中,三个 peg 改变了角色,使得总是一个空 peg 成为缓存。如果您想象钉子不是排成一排而是排成一个圆圈,那么这一点就最容易理解了。与其他问题不同,这里先调用递归,然后完成“实际”移动。

该问题可以被视为与this 问题的重复。

【讨论】:

    【解决方案2】:

    这就是它的作用。起始位置是:

    A|321
    B|
    C|
    

    然后使用moveTower(2,fromA,toC, withB),结果是:

    A|3
    B| 
    C|21
    

    那么,moveDisk(fromA, toB)

    A|
    B|3
    C|21
    

    最后moveTower(2,fromC, toB)结束游戏

    A|
    B|
    C|321
    

    这是河内通常的解决方案:将高度塔 h-1 移动到 withPole,将最大的圆盘移动到 endPole 并将高度塔 h-1 移动到 endPole

    之所以有效,是因为您可以在最大的圆盘上移动高度为h-1 的塔的每个圆盘。

    要做moveTower(height-1,w,x),您可以将所有剩余的圆盘放入所有 3 个塔中。

    所以你将moveTower(height-2,y,z) 然后将第二大的圆盘移动到它的目的地,并再次移动塔的高度为 2。

    编辑: this link 中的图表最好地描述了我想说的(“一张图片胜过一千个单词”)。

    如果您知道要移动 height-1 的塔,那么只需执行算法中描述的 3 个步骤。 moveDisc 是“基本情况”(爬上第一步),moveTower 是递归(如何从步骤n 转到n+1)。

    【讨论】:

      【解决方案3】:

      在这个简单的例子中,您可以通过使用适当的prints 来想象发生了什么,如下所示:

      def moveTower(height,fromPole, toPole, withPole):
          if height >= 1:
              print( "    "*(3-height), "moveTower:", height, fromPole, toPole )
              moveTower(height-1,fromPole,withPole,toPole)
              moveDisk(fromPole,toPole,height)
              moveTower(height-1,withPole,toPole,fromPole)
          #print(withPole)
      
      def moveDisk(fp,tp,height):
          print("    "*(4-height), "moving disk", "~"*(height), "from",fp,"to",tp)
      
      
      moveTower(3,"A","B","C")
      

      输出是:

      moveTower: 3 A B
           moveTower: 2 A C
               moveTower: 1 A B
                   moving disk ~ from A to B
               moving disk ~~ from A to C
               moveTower: 1 B C
                   moving disk ~ from B to C
           moving disk ~~~ from A to B
           moveTower: 2 C B
               moveTower: 1 C A
                   moving disk ~ from C to A
               moving disk ~~ from C to B
               moveTower: 1 A B
                   moving disk ~ from A to B
      

      【讨论】:

      • 非常感谢 :) 在您对输出的解释中,您从 moveTower 函数中省略了一个参数(例如 moveTower: 3 AB,当在我的示例中 moveTower(height, fromPole,toPole, withPole)) 这仅仅是因为第三个参数没有被真正使用吗?我可以摆脱它吗?
      • 这第三个参数是多余但方便的,所以我建议把它留在代码中。输出应该可视化各种递归操作的嵌套。
      • 另外,你的输出中有移动磁盘,我假设这与我的 moveDisk 有关?再次感谢!
      • 对不起,我知道这是不久前的事了,我还是卡住了!我今天回到了这个问题,我意识到我不明白这部分代码的含义: moveTower: 3 AB moveTower: 2 AC moveTower: 1 AB (top 3 lines) 为什么是第 3 行,1 AB 不会不是1 AC吗? @pentadecagon
      【解决方案4】:

      您应该打印每个 moveTower 的调用以查看其参数的变化。递归通常通过参数传播更改。序列号有助于显示顺序(当然,打印到控制台也是有顺序的)。

      def seq_nummer():
          num = 0
          while True:
              num += 1
              yield num
      
      seq_num = seq_nummer()
      
      def moveTower(height, fromPole, toPole, withPole):
          print("seq: %d" % seq_num.next())
          print("height: %d, fromPole: %s, toPole: %s, withPole: %s" % (height, fromPole, toPole, withPole))
          if height >= 1:
              moveTower(height-1, fromPole, withPole, toPole)
              moveDisk(fromPole, toPole)
              moveTower(height-1, withPole, toPole, fromPole)
      
      def moveDisk(fp,tp):
          print("moving disk from",fp,"to",tp)
      
      moveTower(3,"A","B","C")
      

      【讨论】:

        【解决方案5】:
        moveTower(height-1,fromPole,withPole,toPole)
        

        使用第三个极点将除一个之外的所有圆盘从初始极点移动到中间极点。

        moveDisk(fromPole,toPole)
        

        将最后一个圆盘从初始极点移动到最终极点。现在最后一个光盘在正确的位置,不需要移动。

        moveTower(height-1,withPole,toPole,fromPole)
        

        将所有圆盘从中间极移动到最后一极,如果需要,使用第一个极。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-31
          • 2016-01-27
          • 2022-09-27
          • 2012-09-11
          • 1970-01-01
          • 2021-07-06
          • 2014-03-07
          • 1970-01-01
          相关资源
          最近更新 更多