Recursion 使用递归理解河内塔的力学

Recursion 使用递归理解河内塔的力学,recursion,towers-of-hanoi,Recursion,Towers Of Hanoi,我理解求解河内塔的递归算法所做的工作: 例如,如果我们有三个销钉(A、B、C),我们想从A->C移动3张光盘,我们将光盘1和2移动到B,然后将最大的光盘3移动到销钉C,然后将之前移动到B的光盘1和2移动到C。此算法以伪方式表示,如下所示: FUNCTION MoveTower(disk, source, dest, spare): IF disk == 0, THEN: move disk from source to dest ELSE: MoveTow

我理解求解河内塔的递归算法所做的工作:

例如,如果我们有三个销钉(A、B、C),我们想从A->C移动3张光盘,我们将光盘1和2移动到B,然后将最大的光盘3移动到销钉C,然后将之前移动到B的光盘1和2移动到C。此算法以伪方式表示,如下所示:

FUNCTION MoveTower(disk, source, dest, spare):
  IF disk == 0, THEN:
       move disk from source to dest
    ELSE:
       MoveTower(disk - 1, source, spare, dest)   
       move disk from source to dest              
       MoveTower(disk - 1, spare, dest, source)   
  END IF
我打电话:
MoveTower(3,A,C,B)
哪个会调用
MoveTower(2,A,B,C)
哪个会调用
MoveTower(1,A,C,B)
哪个会最终到达将
移动A->B的基本情况

这就是我困惑的地方。当到达基本情况时,我们将A上的顶部磁盘移动到B(在一个快照中),递归如何移动其他所有内容?“后退阶段”如何移动其他光盘(在本例中,除最大的光盘外,所有光盘都移动到B)?它不是只在底部移动顶部光盘吗

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

有人能帮我理解递归在第一次
MoveTower(disk-1,source,spare,dest)
调用中除了到达基本情况之外是如何完成任何事情的吗


谢谢

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

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.
至于“它是如何完成任何事情的”,是这样的:

  • 我们必须使用C柱作为临时存储器,将n个磁盘塔从a柱移动到B柱

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

  • 如果n是1,我们就移动磁盘

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

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

    • 将底部磁盘从A移到B

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


耐心一点,准确一点

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
想象你自己是一台人类计算机,坐在一张舒适的桌子旁,手里拿着大量的纸和铅笔

要调用函数,请将函数配方复制到一张空白纸上,并将其放在面前

要调用另一个函数,请将该函数的配方复制到一张空白的纸上,然后将这张纸放在面前的一堆纸上。无论您是否调用同一个函数,这都无关紧要,因为您正在使用其配方的副本

呼叫移动塔(3,A,C,B)
==>MoveTower_配方{磁盘=3,源=A,目标=C,备用=B}
| 1. 如果磁盘==0,则:
=如果3==0,则:
....
3.其他:
4.调用MoveTower(磁盘-1、源、备用、目标)
=呼叫移动塔(3-1,A,B,C)
==>MoveTower_配方{磁盘=2,源=A,目标=B,备用=C}
| 1. 如果2==0,则:
.....
3.其他:
4.呼叫移动塔(1、A、C、B)
==>MoveTower_配方{磁盘=1,源=A,目标=C,备用=B}
| 1. 如果1==0,则:
3.其他:
4.呼叫移动塔(0、A、B、C)
==>MoveTower_配方{磁盘=0,源=A,目标=B,备用=C}
| 1. 如果0==0,则:
2. ___将磁盘{0}从源{A}移动到目标{B}{uuuuuu(*1)
7.如果结束
.....
.....
看到了吗?
MoveTower
函数配方的副本堆叠在一起
,每个副本都保存着函数命名参数的实际值(在这里,堆栈会向下扩展,但在你的办公桌上,一堆文件会堆积起来)

您可以在最上面的一张纸上沿着配方工作,在其边距上记下您当前在配方线条上的位置,以及各种命名参数和/或命名内部变量(如果有)和/或临时未命名值(如
磁盘-1
)的值

当您处理完最上面的一张纸时,您会将其扔掉,而不是在将其返回值(如果有)复制到现在最上面的一张纸之前,在您输入现在丢弃的配方副本之前的位置

您还可以在您身边的另一张纸上,记录您的程序在现实世界中可能产生的影响(上面标有
(*1)
(*2)
,等等),记录由您的人类计算机执行的输入输出指令,这些指令遵循功能配方(副本)

就这样


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

当您达到基本情况时,不仅生成了第一条输出指令;您还将大量函数配方的副本堆放在面前,每个副本都有相关的数据和状态(当前执行点)

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)
                      ==>
  .....
  .....