Javascript 递归算法如何适用于河内塔?

Javascript 递归算法如何适用于河内塔?,javascript,recursion,towers-of-hanoi,Javascript,Recursion,Towers Of Hanoi,这是我在一本书中解释递归的代码。问题是我不理解该计划采取的步骤: 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

这是我在一本书中解释递归的代码。问题是我不理解该计划采取的步骤:

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");

有人能一步一步地把它分解吗?这对我很有帮助。

我已经弄明白了。分解后,代码按如下方式运行:

var write = function(string) {
document.write(string);
}

var i = 0;

var hanoi = function(disc,src,aux,dst) {
    if (disc > 0) {
    hanoi(disc - 1,src,dst,aux);
    write("Move disc " + disc + " from " + src + " to " + dst + "<br />");
    hanoi(disc - 1,aux,src,dst);
    }
};

hanoi(3,"src","aux","dst");

/*
hanoi(3,"src","aux","dst");
    if (disc > 0) {
    hanoi(2,'src','dst','aux');
        if (disc > 0) {
        hanoi(1,'src','aux','dst');
            if (disc > 0) {
            hanoi(0,'src','dst','aux');
                END
            write("Move disc " + 1 + " from " + src + " to " + dst + "<br />");
            hanoi(0,'aux','src','dst');
                END
            }
        write("Move disc " + 2 + " from " + src + " to " + dst + "<br />");
        hanoi(1,'dst','src','aux');
            if (disc > 0) {
            hanoi(0,'src','dst','aux');
                END
            write("Move disc " + 1 + " from " + src + " to " + dst + "<br />");
            hanoi(0,'aux','src','dst');
                END
            }
        }
    write("Move disc " + 3 + " from " + src + " to " + dst + "<br />");
    hanoi(2,'aux','src','dst');
        if (disc > 0) {
        hanoi(1,'aux','dst','src');
            if (disc > 0) {
            hanoi(0,'src','dst','aux');
                END
            write("Move disc " + 1 + " from " + src + " to " + dst + "<br />");
            hanoi(0,'aux','src','dst');
                END
            }
        write("Move disc " + 2 + " from " + src + " to " + dst + "<br />");
        hanoi(1,'src','aux','dst');
            if (disc > 0) {
            hanoi(0,'src','dst','aux');
                END
            write("Move disc " + 1 + " from " + src + " to " + dst + "<br />");
            hanoi(0,'aux','src','dst');
                END
            }
        }
    }
*/
var write=函数(字符串){
document.write(字符串);
}
var i=0;
var hanoi=功能(磁盘、src、辅助、dst){
如果(光盘>0){
河内(disc-1、src、dst、aux);
写入(“将光盘”+光盘+”从“+src+”移动到“+dst+”
); 河内(disc-1、辅助、src、dst); } }; 河内(3,“src”、“aux”、“dst”); /* 河内(3,“src”、“aux”、“dst”); 如果(光盘>0){ 河内(2,'src','dst','aux'); 如果(光盘>0){ 河内(1,'src','aux','dst'); 如果(光盘>0){ 河内(0,'src','dst','aux'); 结束 写入(“将光盘“+1+”从“+src+”移动到“+dst+”
); 河内(0,'aux','src','dst'); 结束 } 写入(“将光盘“+2+”从“+src+”移动到“+dst+”
”); 河内(1,'dst','src','aux'); 如果(光盘>0){ 河内(0,'src','dst','aux'); 结束 写入(“将光盘“+1+”从“+src+”移动到“+dst+”
); 河内(0,'aux','src','dst'); 结束 } } 写入(“将光盘“+3+”从“+src+”移动到“+dst+”
”); 河内(2,'aux','src','dst'); 如果(光盘>0){ 河内(1,'aux','dst','src'); 如果(光盘>0){ 河内(0,'src','dst','aux'); 结束 写入(“将光盘“+1+”从“+src+”移动到“+dst+”
); 河内(0,'aux','src','dst'); 结束 } 写入(“将光盘“+2+”从“+src+”移动到“+dst+”
”); 河内(1,'src','aux','dst'); 如果(光盘>0){ 河内(0,'src','dst','aux'); 结束 写入(“将光盘“+1+”从“+src+”移动到“+dst+”
); 河内(0,'aux','src','dst'); 结束 } } } */

关于这一点,最令人困惑的部分是可视化第一个递归循环的结束。只有当disc==0时,disc==3的语句才会最终被写入。

也许解决河内塔楼问题的最简单方法是这样的:

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
要将
x
盘从销钉A移动到销钉C,使用销钉B作为“辅助”销钉:

  • 使用销钉C作为辅助销钉,将
    x-1
    盘从销钉A移动到销钉B
  • x
    第四张光盘从销钉A移动到销钉C(无需辅助销钉,因为您只移动一张光盘)
  • 使用销钉A作为辅助销钉,将
    x-1
    盘从销钉B移动到销钉C
  • 请注意,要移动
    x
    光盘,必须移动
    x-1
    光盘。您可以使用相同的功能移动这些
    x-1
    光盘,只需切换哪些销钉是源销钉、目的销钉和辅助销钉。这就是为什么《河内之塔》是递归的一个常见例子,这就是你需要在一个问题中看到的模式,以便让递归为你工作。当然,它不必是“移动
    x-1
    discs”,也可以是类似“列出此子文件夹”的内容。树(比如带有子文件夹的目录等)是递归的另一个亮点。与其他作业一样,为了在项目上执行作业,您可能需要在子项目上执行相同的作业

    现在,为了得到有用的递归,您需要一个“基本情况”——递归将停止的条件。如果不这样做,代码将永远运行(或者至少直到内存耗尽或溢出调用堆栈)。这里的基本情况发生在
    x==0
    时(因为移动0个光盘意味着你什么也不做,因为函数的核心是
    if
    )。也可能是当
    x==1
    时,因为这样就不必递归,但是在每次
    hanoi
    调用之前额外的
    if
    会增加一些噪音(递归解决方案的主要好处是它的简单性)。无论如何,当
    x==0
    时,函数将返回,而不执行任何操作。调用它的函数(它有
    x==1
    )现在可以继续做它的事情了——在本例中,说“将光盘1从src移动到dest”,然后在参数切换的情况下再次调用
    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
    

    您是否阅读了可能的副本?另外:可能的副本请检查我的答案,并详细说明步骤。如果您想问另一个问题,请在实际的新问题中提问,因为没有人会知道在您的答案中查找问题DHere是java中完整的最短源代码