这是我解释递归的书中的代码。问题是我不明白程序采取的步骤:
var hanoi = function(disc,src,aux,dst) {
if (disc > 0) {
hanoi(disc - 1,src,dst,aux);
document.write("Move disc " + disc + " from " + src + " to " + dst + "<br />");
hanoi(disc - 1,aux,src,dst);
}
};
hanoi(3,"src","aux","dst");
输出是这样写的:
Move disc 1 from src to dst
Move disc 2 from src to aux
Move disc 1 from dst to aux
Move disc 3 from src to dst
Move disc 1 from aux to src
Move disc 2 from aux to dst
Move disc 1 from src to dst
有人可以一步一步分解吗?这对我很有帮助。
最佳答案
可能是汉诺塔最简单的解决方案是这样的:
将 x
个圆盘从桩 A 移动到桩 C,使用桩 B 作为“辅助”桩:
- 将
x-1
个圆盘从桩 A 移到桩 B,使用桩 C 作为辅助桩。 - 将第
x
个圆盘从桩 A 移到桩 C(不需要辅助桩,因为您只移动一张圆盘)。 - 将
x-1
圆盘从桩 B 移到桩 C,使用桩 A 作为辅助桩。
请注意,要移动 x
个圆盘,您必须移动 x-1
个圆盘。您可以只使用相同的功能来移动那些 x-1
圆盘,并且只需切换哪些钉是源钉、目标钉和辅助钉。这就是使汉诺塔成为递归的常见例子的原因,这也是您需要在问题中看到的那种模式,以便使递归为您工作。它不一定是“移动 x-1
光盘”,当然......它可以是“列出这个子文件夹”之类的东西。树(如带有子文件夹等的目录)是递归发挥作用的另一个地方。与其他工作一样,为了在一个项目上完成工作,您可能需要在子项目上做同样的工作。
现在,为了实现有用的递归,您需要一个“基本情况”——递归停止的条件。如果不这样做,代码将永远运行(或者至少直到它用完内存或溢出调用堆栈)。这里的基本情况发生在 x == 0
时(因为移动 0 个圆盘意味着你什么都不做,因为 if
围绕着函数的核心)。也可能是当 x == 1
时,因为那时您不必递归,但每次 hanoi
调用之前的额外 if
会添加一点噪音(递归解决方案的主要好处是它的简单性)。无论如何,当 x == 0
时,函数不做任何事情就返回。调用它的函数(它有 x == 1
)现在开始继续做它的事情——在这种情况下,说“将光盘 1 从 src 移动到目标”,然后调用 hanoi
参数切换后再次运行。
流程有点像这样:
hanoi(3, src, aux, dest)
hanoi(2, src, dest, aux)
hanoi(1, src, aux, dest)
hanoi(0, src, dest, aux) // no op
print "Move 1 from src to dest"
hanoi(0, aux, src, dest) // no op
print "Move 2 from src to aux"
hanoi(1, dest, src, aux)
hanoi(0, dest, aux, src) // no op
print "move 1 from dest to aux"
hanoi(0, src, dest, aux) // no op
print "move 3 from src to dest"
hanoi(2, aux, src, dest)
hanoi(1, aux, dest, src)
hanoi(0, aux, src, dest) // no op
print "Move 1 from aux to src"
hanoi(0, dest, aux, src) // no op
print "Move 2 from aux to dest"
hanoi(1, src, aux, dest)
hanoi(0, src, dest, aux) // no op
print "move 1 from src to dest"
hanoi(0, aux, src, dest) // no op
关于javascript - 递归算法如何适用于汉诺塔?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6947653/