【问题标题】:How does recursive algorithm work for Towers of Hanoi?递归算法如何适用于河内塔?
【发布时间】:2011-10-20 07:57:18
【问题描述】:

这是我解释递归的书中的代码。问题是我不明白程序采取的步骤:

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

有人可以逐步分解吗?这对我很有帮助。

【问题讨论】:

标签: javascript recursion towers-of-hanoi


【解决方案1】:

可能最简单的河内塔解决方案是这样的:

要将x 光盘从钉子 A 移动到钉子 C,使用钉子 B 作为“辅助”钉子:

  1. x-1 圆盘从挂钉 A 移到挂钉 B,使用挂钉 C 作为辅助挂钉。
  2. x'th 圆盘从 peg A 移到 peg C(不需要辅助 peg,因为您只需移动一个圆盘)。
  3. 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移动到dest”,然后在args切换的情况下再次调用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

【讨论】:

    【解决方案2】:

    我想通了。分解后,代码运行如下:

    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
                }
            }
        }
    */
    

    这方面最令人困惑的部分是可视化第一个递归循环的 END。只有在 disc == 0 时,disc == 3 的语句才会最终被写入。

    【讨论】:

    猜你喜欢
    • 2012-09-11
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 2021-02-21
    相关资源
    最近更新 更多