Python 河内巨蟒之塔-理解递归
我是Python的新手,目前正在复习关于河内塔和递归的教程。我以为我理解递归,直到他们给出这个例子:Python 河内巨蟒之塔-理解递归,python,algorithm,recursion,towers-of-hanoi,Python,Algorithm,Recursion,Towers Of Hanoi,我是Python的新手,目前正在复习关于河内塔和递归的教程。我以为我理解递归,直到他们给出这个例子: def moveTower(height,fromPole, toPole, withPole): if height >= 1: moveTower(height-1,fromPole,withPole,toPole) moveDisk(fromPole,toPole) moveTower(height-1,withPole,toP
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
我的问题是,它是怎么做到的?!有人能检查一下代码行,让我明白它是如何打印正确的动作的吗?我主要困惑于fp
和tp
的值如何从A
变为B
变为C
。对不起,如果这是一个有点广泛的问题!任何帮助都将不胜感激 本主题已涵盖,但是,如果不熟悉递归方法的概念,递归方法可能会令人困惑。该算法的工作原理是,首先通过缓存销钉递归移动除最后一个磁盘(一个较小的问题实例)以外的所有磁盘,然后“实际”将最后一个磁盘移动到目标销钉,然后将塔移动到初始销钉。实际上,依赖于递归,底部的磁盘被移动到目标peg,这是不可能直接执行的,因为没有有效的移动。在递归调用中,三个peg更改角色,使空peg始终成为缓存。如果你想象钉子不是排列成一条直线而是成一个圆圈,这一点最容易理解。与其他问题不同,这里递归调用首先出现,然后完成“实际”移动
这个问题可以看作是问题的复制品。下面是它的作用。起始位置为:
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
移动到带杆,将最大的圆盘移动到端杆
,并将高度塔h-1
移动到端杆
这是因为您可以在最大的圆盘上移动高度塔的每个圆盘h-1
要执行移动风塔(高度-1,w,x)
您可以将所有剩余的圆盘放置在所有3个风塔中
因此,您将移动塔架(高度-2,y,z)
然后将第二大光盘移动到其目的地,然后再次移动塔架高度-2
编辑:
这张图表最好地描述了我想说的内容(“一幅画抵得上千言万语”)
如果您知道要移动高度为1的塔,只需执行算法中描述的3个步骤即可moveDisc
是“基本情况”(爬上第一步),moveTower是递归(如何从步骤n
到n+1
)。在这个简单的情况下,您可以通过使用适当的打印来可视化发生的情况,如下所示:
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的调用,以查看其参数中的更改。递归通常通过参数传播更改。序列号有助于显示顺序(当然,控制台的打印也有顺序)
使用第三极将除一个外的所有圆盘从初始极移到中间极
moveDisk(fromPole,toPole)
将最后一个圆盘从初始极移到最终极。现在,最后一个光盘位于正确位置,无需移动
moveTower(height-1,withPole,toPole,fromPole)
如果需要,使用第一个磁极将所有光盘从磁极之间移动到最后一个磁极。也许这个答案很有用:我建议将打印(高度、fromPole、toPole、withPole)
粘贴在顶部,看看会发生什么!非常感谢所有回答问题的人!现在对我的理解更加自信:)非常感谢:)在您对输出的解释中,您省略了moveTower函数中的一个参数(例如moveTower:3ab,在我的示例中,moveTower(高度、fromPole、toPole、withPole))这仅仅是因为第三个参数没有真正使用吗?我可以去掉它吗?第三个参数是多余的,但是很方便,所以我建议把它留在代码中。输出应该是可视化各种递归操作的嵌套。另外,在输出中有移动磁盘,我假设这与我的移动磁盘有关?再次感谢!对不起,我知道这是很久以前的事了,我还是卡住了!今天我回到这里,我意识到我不明白在代码的这一部分:移动塔:3 A B移动塔:2 A C移动塔:1 A B(最上面的3行)为什么第3行是1 AB不是1 AC@十五边形
moveDisk(fromPole,toPole)
moveTower(height-1,withPole,toPole,fromPole)