使用递归了解河内塔的机理

时间:2018-07-10 23:33:28

标签: recursion towers-of-hanoi

我了解解决河内塔的递归算法在做什么:

例如,如果我们有三个钉(A,B,C),并且要从A-> C移动3个光盘,则将光盘1和2移至B,然后将最大的光盘3移至钉C,然后将之前移至B的光盘1和2移至C。此算法以伪方式表示,其方式如下:

MoveTower(3,A,C,B)

我进行呼叫:MoveTower(2,A,B,C)将呼叫MoveTower(1,A,C,B),后者将呼叫move A -> B,最终将达到基本情况,MoveTower(disk - 1, source, spare, dest)

这是我感到困惑的地方。到达基本情况时,我们将A上的顶部磁盘移到B上(一次拍摄)递归如何移动其他所有内容? “回退阶段”如何移动其他光盘(在这种情况下,是所有光盘,但最大的是B)?难道不是只在基础盒中移动顶部光盘吗?

例如,我知道在达到基本情况之后的阶乘函数中,递归“返回”一个值,该值传递给上一个调用,该值一直传递到上一个调用,直到顶部调用。在每个级别上,它都在等待递归返回。

有人可以帮助我理解递归如何在第一个getPW调用中完成除达到基本情况之外的任何事情?

谢谢

2 个答案:

答案 0 :(得分:3)

要有耐心,而且要准确。

FUNCTION MoveTower(disk, source, dest, spare):
1.  IF disk == 0, THEN:
2.       move disk from source to dest
3.    ELSE:
4.       MoveTower(disk - 1, source, spare, dest)   
5.       move disk from source to dest              
6.       MoveTower(disk - 1, spare, dest, source)   
7.  END IF

想象自己是一台人类计算机,坐在舒适的办公桌旁,有很多纸和铅笔。

要调用功能,请将功能配方复制到一张空白的纸上,然后放在您的面前。

要调用另一个功能,请将该功能的配方复制到一张空纸上,然后将该纸放在您前面的纸叠中。 >可以是否,例如,可以使用相同的函数。

CALL MoveTower(3, A, C, B)
==> MoveTower_recipe{ disk=3, source=A, dest=C, spare=B }
  | 1. IF disk==0, THEN:
     = IF 3   ==0, THEN:
        ....
    3. ELSE:
    4. CALL MoveTower(disk - 1, source, spare, dest) 
       = CALL MoveTower(3-1, A, B, C)
       ==> MoveTower_recipe{ disk=2, source=A, dest=B, spare=C }
         | 1. IF 2 == 0 THEN:
             .....
           3. ELSE:
           4. CALL MoveTower( 1, A, C, B)
               ==> MoveTower_recipe{ disk=1, source=A, dest=C, spare=B }
                 | 1. IF 1 == 0 THEN:
                   3. ELSE:
                   4. CALL MoveTower(0, A, B, C)
                        ==> MoveTower_recipe{ disk=0, source=A, dest=B, spare=C }
                          | 1. IF 0 == 0 THEN:
                            2. ___move disk{0} from source{A} to dest{B}___      (*1)
                            7. END IF
                        <==
                   5. ___move disk{1} from source{A} to dest{C}___               (*2)
                   6. CALL MoveTower( 0, C, B, A)
                      ==>
  .....
  .....

看到了吗? MoveTower函数配方的 副本 彼此 堆叠 它自己的函数命名参数的实际值(此处,堆栈在视觉上向下增长,但是在您的办公桌上,一堆文件将堆积起来)。

您可以按照最上面一张纸上的配方进行操作,在其边距上记下当前沿配方行的位置以及各种命名参数和/或命名内部变量(如果有)和/的值。或临时未命名值(例如disk - 1)。

在处理完最上面的纸后,您要遍历全部,而不是将其返回值(如果有)复制到现在位于您所在的地方的最上面的纸上 输入现在废弃的食谱副本之前。

您还可以注意到计算机按照功能配方(的副本)在您身边的另一张纸上记录的效果,并由人机执行,记录下的效果。程序所具有的真实世界(上面标有(*1)(*2)等)。

就是这样。


计算状态记录在堆栈中每个配方副本的边距中。

达到基本情况时,不仅产生了第一条输出指令,而且还产生了第一条输出指令。您还已经在自己面前堆积了很多功能配方的副本,每个副本都有其关联的数据和状态(当前执行点)。

答案 1 :(得分:0)

您必须在脑海中形象化呼叫树:

MoveTower 3, from A, to B, using C:
1. MoveTower 2, from A, to C, using B:
   1.1. MoveTower 1, from A, to B, using C:
        1.1.1. Move disk 1 from A to B.
   1.2. Move disk 2 from A to C.
   1.3. MoveTower 1, from B, to C, using A:
        1.3.1. Move disk 1 from B to C.
2. Move disk 3 from A to B.
3. MoveTower 2, from C, to B, using A:
   3.1. MoveTower 1, from C, to A, using B:
        3.1.1. Move disk 1 from C to A.
   3.2. Move disk 2 from C to B.
   3.3. MoveTower 1, from A, to B, using C:
        3.3.1. Move disk 1 from A to B.

现在,如果我们仅读取“移动磁盘”操作,则将具有:

Move disk 1 from A to B.
Move disk 2 from A to C.
Move disk 1 from B to C.
Move disk 3 from A to B.
Move disk 1 from C to A.
Move disk 2 from C to B.
Move disk 1 from A to B.

关于“它如何完成任何事情”,就像这样:

  • 我们必须将一堆 n 个磁盘塔从帖子A移到帖子B,并使用帖子C作为临时存储。

  • 有两种可能性, n 为1,或者 n 大于1。

  • 如果 n 为1,则只需移动磁盘。

  • 如果 n 大于1,我们分三步进行:

    • 使用B作为临时存储,将较小的 n − 1 个磁盘塔从A移动到C。

    • 将底部磁盘从A移到B。

    • 使用A作为临时存储,将较小的 n-1 个磁盘塔从C移到B。