解决河内塔的简单递归代码:
public static void hanoi(char A, char B, char C, int n) {
if(n>0) {
hanoi(A,C,B,n-1);
System.ouit.println("moving from " + A + " to " + B);
hanoi(C,B,A,n-1);
}
}
我和我的同学今天检查了这段代码,虽然我们知道它是如何工作的,但我们无法理解算法,这意味着我们永远不会想到这样的解决方案。
我确实记得老师曾经说过,我们不关心它是如何解决的,我们只是假设它是。他指的是函数自称的部分。
我知道我们正在分两步解决河内塔楼问题。首先将所有环移动到C(这是来自老师的代码,在这种情况下我们想要将所有环移动到B而不是C),然后将最大的环移动到B,然后将所有剩余的环从C移动到B.我明白了在第一次调用中,我们从A移动到C,第二次从C移动到B. 我在纸上写了代码如何执行并得到正确的打印,但我仍然不明白。我理解,但我不明白,如果你明白我的意思。
ps:我查了很多我发现的视频和链接,没有给我任何有价值的答案,你怎么会想到这样的算法。这与例如斐波那契序列不同,这是合乎逻辑的。但是......
编辑:我很难解释我不理解的东西,我之前从未遇到过编程问题。我知道这段代码是如何工作的,我可以在纸上写下整个程序。我知道如何解决河内塔。但如果你给我一个为河内塔写算法的任务,我永远不会想到这一点。我正在看这个代码,我说,这个代码到底是怎么给出正确的打印输出?我对这种信仰的飞跃有一个问题,但不知怎的,这就是递归的工作原理。基本上前2个环我理解这个算法是有效的。但是从那时起,移动环是不同的,因为你已经有2个戒指坐在钉子上,你必须移动它们才能移动更多的戒指,然后把那些旧戒指放回去。呃,我从来没有遇到编程问题,直到现在,这真的很困扰我,因为这只是一个开始,它应该是如此简单和合乎逻辑,我们的老师甚至懒得解释这是如何工作的,他只是给了我们代码并感动上。
答案 0 :(得分:1)
将对hanoi
函数的调用视为"使用主轴C作为备用"将整堆n
磁盘从主轴A移动到主轴B.如果您愿意假设它可以完成,请将其概念化为函数调用。几分钟之后应该清楚这可以通过将具有n-1
磁盘的底盘()从主轴A移动到备用主轴C,移动来实现。将底部磁盘移动到其目标主轴B,然后将备用堆上的堆从C移动到B.由于移动堆被认为是函数调用,所以堆移动是通过在移动底部之前和之后的递归调用来完成的。磁盘。唯一剩下的问题是要确认什么时候不能再做了。这是由您的n
计数器完成的,它表示要移动的堆中的磁盘数。如果它为零,则不需要采取任何措施。
河内的塔是信仰的递归跳跃的一个很好的例子,"您可以通过函数调用来假设解决方案,然后将函数应用于一个或多个子问题+一个简单的案例。
答案 1 :(得分:0)
从47:15开始,看看是否有帮助:http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/1b-procedures-and-processes-substitution-model/。这些课程令人惊叹,不仅仅是历史性的。其中,河内塔。不要担心在lisp中给出的课程,这是相同的原则。