Recursion 河内塔:递归算法

Recursion 河内塔:递归算法,recursion,towers-of-hanoi,Recursion,Towers Of Hanoi,尽管我在理解递归方面没有任何问题,但我似乎无法理解河内塔问题的递归解决方案。以下是以下代码: 我理解基本情况和将问题分解为更小的部分直到能够移动单个磁盘的概念。但是,我无法理解非基类中的两个递归调用是如何协同工作的。也许有人能帮我?谢谢。事实上,也提供了一个解释: 要将n个盘从销钉A移动到销钉C: 移动−1个圆盘从A到B。这使得圆盘n单独位于销钉A上 将光盘n从A移到C 移动−1从B到C的光盘,使其位于光盘上#n 很明显,首先必须删除n− 1张光盘以访问第n张光盘。你必须先把它们移到另一个木桩上

尽管我在理解递归方面没有任何问题,但我似乎无法理解河内塔问题的递归解决方案。以下是以下代码:

我理解基本情况和将问题分解为更小的部分直到能够移动单个磁盘的概念。但是,我无法理解非基类中的两个递归调用是如何协同工作的。也许有人能帮我?谢谢。

事实上,也提供了一个解释:

要将n个盘从销钉A移动到销钉C:

  • 移动−1个圆盘从A到B。这使得圆盘n单独位于销钉A上
  • 将光盘n从A移到C
  • 移动−1从B到C的光盘,使其位于光盘上#n
  • 很明显,首先必须删除n− 1张光盘以访问第n张光盘。你必须先把它们移到另一个木桩上,而不是你想要整座塔出现的地方

    除了光盘数量外,您文章中的代码还有三个参数:一个源peg、一个目标peg和一个临时peg,在这三个参数之间可以存储光盘(每个大小为n的光盘)− 1(适合)


    递归实际上发生了两次,一次在写入之前,一次在写入之后。
    writeln
    前面的一个将移动n− 1使用目标peg作为临时存储(递归调用中的参数顺序不同),将光盘刻录到临时peg上。之后,剩余的圆盘将被移动到目标桩,然后第二次递归通过移动n来强制整个塔的移动− 从临时桩到目标桩的1个塔,位于圆盘n上方。

    我同意,当你第一次看到它时,这个塔不是立即出现的,但当你开始研究它时,它相当简单

    基本情况:您的塔的大小为1。所以你可以一步到位,从源代码直接到目标代码

    递归案例:您的塔的大小n>1。因此,您将大小为n-1的顶部塔架移动到一个额外的桩号(by),将大小为1的底部“塔架”移动到目标桩号,并将顶部塔架从by移动到dest

    通过一个简单的例子,你有一个高度为2的塔:

     _|_    |     |
    __|__   |     |
    ===== ===== =====
    
    第一步:将2-1(=1)的塔顶移动到额外的木桩上(比如说中间的木桩)

    下一步:将底部光盘移动到目标:

      |     |     |
      |    _|_  __|__
    ===== ===== =====
    
    最后,将(2-1)=1的塔顶移动到目的地

      |     |    _|_
      |     |   __|__
    ===== ===== =====
    

    如果您仔细想想,即使塔是3个或更多个,也总会有一个空的额外桩,或者一个包含所有较大圆盘的桩,供递归在交换塔时使用。

    第一个递归调用使用dest作为辅助桩,将所有块(最大的块除外)从源移动到源。完成后,除了最大的一块外,所有的碎片都将躺在地上,最大的一块是免费的。现在您可以将最大的一个移动到dest,并使用另一个递归调用将所有片段从by移动到dest


    递归调用不会知道关于最大部分的任何信息(即,它们会忽略它),但这没关系,因为递归调用只处理较小的部分,因此可以自由地在最大部分上移动和移动。

    关于递归Hanoi实现,这里有一个很好的解释


    概括地说,如果你想把底板从棒A移到棒B,你首先必须把它上面的所有较小的板从棒A移到棒C。第二个递归调用是在你的基本情况将单个大板从棒A移到棒B之后,把你移到C的板移回棒B上。

    这很简单。假设你想从A移到C

    如果只有一个磁盘,就移动它

    如果有多个磁盘,请执行以下操作

    • 将除底部磁盘以外的所有磁盘(n-1个磁盘)从A移动到B
    • 将底部磁盘从A移到C
    • 将第一步中的n-1个磁盘从A移动到C
    请记住,在移动n-1个磁盘时,第n个磁盘根本不是问题(一旦它比所有其他磁盘都大)


    请注意,移动n-1个磁盘会在同一个问题上再次出现,直到n-1=1,在这种情况下,您将处于第一个if(您应该移动它的位置)。

    作为一名CS学生,您可能听说过数学归纳法。
    河内塔的递归解也有类似的作用——唯一不同的部分是,不要像整座塔一样迷失在B和C中。

    一年前,我参加了函数编程课程,并为算法绘制了这幅插图。 希望有帮助

    (0)  _|_         |          |
        __|__        |          |
       ___|___       |          |
      ____|____  ____|____  ____|____
    
    (1.1) |          |          |
        __|__        |          |
       ___|___      _|_         |
      ____|____  ____|____  ____|____ (A -> B)
    
    (1.2) |          |          |
          |          |          |
       ___|___      _|_       __|__
      ____|____  ____|____  ____|____ (A -> C)
    
    (1.3) |          |          |
          |          |         _|_
       ___|___       |        __|__
      ____|____  ____|____  ____|____ (B -> C)
    
    
    
    (2.1) |          |          |
          |          |         _|_
          |       ___|___     __|__
      ____|____  ____|____  ____|____ (A -> B)
    
    
    
    (3.1) |          |          |
          |          |          |
         _|_      ___|___     __|__
      ____|____  ____|____  ____|____ (C -> A)
    
    (3.2) |          |          |
          |        __|__        |
         _|_      ___|___       |
      ____|____  ____|____  ____|____ (C -> B)
    
    (3.3) |         _|_         |
          |        __|__        |
          |       ___|___       |
      ____|____  ____|____  ____|____ (A -> B)
    
    三环问题已拆分为两个二环问题(1.x和3.x)

    塔台(N,源,辅助目标):

  • if N =1 Then
       Write : Source -> dest
       return
    end of if
    
  • 将N-1磁盘从peg源移动到peg aux

    call Tower (N-1, source, dest, aux)
    
  • 写入源->目标
  • 将N-1个磁盘从peg aux移动到peg dest

    call Tower (N-1, source, dest, aux)
    
  • 返回

  • 将其视为一个堆栈,磁盘直径由整数(4,3,2,1)表示 第一个递归调用将被调用3次,从而填充运行时堆栈,如下所示

  • 第一个电话:1。第二次呼叫:2,1。第三次呼叫:3,2,1
  • 在第一次递归结束后,运行时堆栈的内容从最大直径到最小直径(先进先出)弹出到中间极点。接下来,将直径为4的磁盘移动到目标位置

      |     |    _|_
      |     |   __|__
    ===== ===== =====
    

    第二个递归调用与第一个递归调用相同,只是将元素从中间极点移动到目标

    假设我们要通过B将光盘从a移动到C,然后:

  • 将较小的光盘移到B
  • 将另一张光盘移到C
  • 把B移到C
  • 从A移到B
  • 将全部从C移到A

  • 如果您重复上述所有步骤,光盘将传输。

    我也在尝试获取递归

    我找到了一种我认为

    我认为它就像一个步骤链(步骤不是常数,它可能会根据前一个节点而变化)

    我必须想出两件事:

  • 上一节点
  • 阶梯式
  • 这一步之后还有什么
    call Tower (N-1, source, dest, aux)
    
    function =
    
    n*f(n-1) 
    
    its 2 steps process
    from a-->to step--->b
    
    hanoi(4, "src", "aux", "dst");
    if (disc > 0) {
        hanoi(3, 'src', 'dst', 'aux');
            if (disc > 0) {
                hanoi(2, 'src', 'aux', 'dst');
                    if (disc > 0) {
                        hanoi(1, 'src', 'dst', 'aux');
                            if (disc > 0) {
                                hanoi(0, 'src', 'aux', 'dst');
                                    END
                            document.writeln("Move disc" + 1 + "from" + Src + "to" + Aux);
                            hanoi(0, 'aux', 'src', 'dst');
                                    END
                            }
    
    (define (th n a b c)
        (if (zero? n) 'done
            (begin
               (th (- n 1) a c b)
               (display (list a c))
               (newline)
               (th (- n 1) b a c))))
    (th 5 'source 'spare 'destination)
    
    solve(n,s,i,d) //solve n discs from s to d, s-source i-intermediate d-destination
    {
        if(n==0)return;
        solve(n-1,s,d,i); // solve n-1 discs from s to i Note:recursive call, not just move
        move from s to d; // after moving n-1 discs from s to d, a left disc in s is moved to d
        solve(n-1,i,s,d); // we have left n-1 disc in 'i', so bringing it to from i to d (recursive call)
    }
    
    public void TOH(int n, int A , int B , int C){
        if (n>0){
            TOH(n-1,A,C,B);
            System.out.println("Move a disk from tower "+A +" to tower " + C);
            TOH(n-1,B,A,C);
        }
    }
    
    public static void main(String[] args) {
        new TowerOfHanoi().TOH(3, 1, 2, 3);
    }   
    
    public static void hanoi(int number, String source, String aux, String dest)
    {
        if (number == 1)
        {
            System.out.println(source + " - > "+dest);
        }
        else{
            hanoi(number -1, source, dest, aux);
            hanoi(1, source, aux, dest);
            hanoi(number -1, aux, source, dest);
        }
    }
    
    procedure Hanoi(n, A, B, C);
      if n == 1
        move ring n from peg A to peg B
      else
        Hanoi(n-1, A, C, B);
        move ring n-1 from A to C
        Hanoi(n-1, C, B, A);
    end;
    
    private static String SOURCE_PEG = "B";
    
    private static String SPARE_PEG = "C";
    
    private static String TARGET_PEG = "A";
    
    public void listSteps(int n, String source, String target, String spare) {
        if (n == 1) {
            System.out.println("Please move from Peg " + source + "\tTo Peg\t"
                    + target);
        } else {
            listSteps(n - 1, source, spare, target);
            listSteps(1, source, target, spare);
            listSteps(n - 1, spare, target, source);
        }
    }
    
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        new TowerOfHanoi().listSteps(18, SOURCE_PEG, TARGET_PEG, SPARE_PEG);
    
        long endTime = System.currentTimeMillis();
    
        System.out.println("Done in " + (endTime - startTime) / 1000
                + "\t seconds");
    }
    
    void TOH(int n, int a, int b){
            /*Assuming a as source stack numbered as 1, b as spare stack numbered as 2 and  c as target stack numbered as 3. So once we know values of a and b, we can determine c as there sum is a constant number (3+2+1=)6.
           */
    int c = 6-a-b;
    if(n==1){
        cout<<"Move from "<<a<<" to "<<b<<"\n";
    }
    else{
        // Move n-1 disks from 1st to 2nd stack. As we are not allowed to move more than one disks at a time, we do it by recursion. Breaking the problem into a simpler problem.
        TOH(n-1, a, c);
        // Move the last alone disk from 1st to 3rd stack.
        TOH(1, a, b);
        // Put n-1 disks from 2nd to 3rd stack. As we are not allowed to move more than one disks at a time, we do it by recursion. Breaking the problem into a simpler problem.        
        TOH(n-1, c, b);
    }
    }
    int main() {
    
    TOH(2, 1, 3);
    cout<<"FINISHED                        \n";
    TOH(3, 1, 3);
    cout<<"FINISHED                        \n";
    TOH(4, 1, 3);
    return 0;
    }
    
    1. Movetower(3,a,b,c)  // No Move needed
    2. Movetower(2,a,c,b)  // No move needed
    3. Movetower(1,a,b,c)  // Here is the time to move, move disc1 from a to b
    4. Movetower(2,a,c,b)  // Returning to this call again, this is the time to move disc2 from a to c
    5. Movetower(1,b,c,a)  // Again the time to move, this time disc1 from b to c
    6. Movetower(3,a,b,c)  // Returning to this call again, this is the time to move disc3 from a to b
    7. Movetower(2,c,b,a)  // Not the time to move
    8. Movetower(1,c,a,b)  // Here is the time to move, move disc1 from c to a
    9. Movetower(2,c,b,a)  // Returning to this call again, this is the time to move disc2 from c to b
    10.Movetower(1,c,a,b)  // Here is the time to move, move disc1 from a to b
    
    def Hanoi(n, A, B, C):
        if(n==1): print "move plates to empty peg"
        else:
           Hanoi(n-1, A, B, C)
           print "move"+str(n)+" to peg "+C
           Hanoi(n-1, B, C, A)
    
    private void towersOfHanoi(int n, char source, char destination, char helper) {
        //Base case, If there is only one disk move it direct from source to destination
        if(n==1){
            System.out.println("Move from "+source+" to "+destination);
        }
        else{
            //Step1: Move the top n-1 disks from source to helper
            towersOfHanoi(n-1, source, helper, destination);
            //Step2: Move the nth disk from source to destination
            System.out.println("Move from "+source+" to "+destination);
            /*Step3: Move the n-1 disks(those you moved from source to helper in step1) 
             * from helper to destination, using source(empty after step2) as helper
             */
            towersOfHanoi(n-1, helper, destination, source);
        }
    }
    
    import "fmt"
    
    func main() {
        toi(4, "src", "dest", "swap")
    }
    
    func toi(n int, from, to, swap string) {
        if n == 0 {
            return
        }
        if n == 1 {
            fmt.Printf("mov %v %v -> %v\n", n, from, to)
            return
        }
        toi(n-1, from, swap, to)
        fmt.Printf("mov %v %v -> %v\n", n, from, to)
        toi(n-1, swap, to, from)
    }`
    
    # Hanoi towers puzzle
    # for each n, you have to move n-1 disks off the n disk onto another peg
    # then you move the n disk to a free peg
    # then you move the n-1 disks on the other peg back onto the n disk
    
    def hanoi(n):
        if n == 1:
            return 1
        else:
            return hanoi(n-1) + 1 + hanoi(n-1)
    
    
    for i in range(1, 11):
        print(f"n={i}, moves={hanoi(i)}")
    
    n=1, moves=1
    n=2, moves=3
    n=3, moves=7
    n=4, moves=15
    n=5, moves=31
    n=6, moves=63
    n=7, moves=127
    n=8, moves=255
    n=9, moves=511
    n=10, moves=1023
    
    def moveTower(height,fromPole, toPole, withPole, ar = ''):
        if height >= 1:
            print( "    "*(3-height), "moveTower:", height, fromPole, toPole, ar )
            moveTower(height-1,fromPole,withPole,toPole)
            moveDisk(fromPole,toPole,height)
            moveTower(height-1,withPole,toPole,fromPole, '*')
        #print(withPole)
    
    def moveDisk(fp,tp,height):
        print("    "*(4-height), "moving disk", "~"*(height), "from",fp,"to",tp)
    
    
    moveTower(3,"A","B","C")
    
     moveTower: 3 A B 
         moveTower: 2 A C 
             moveTower: 1 A B 
                 moving disk ~ from A to B
             moving disk ~~ from A to C
             moveTower: 1 B C *
                 moving disk ~ from B to C
         moving disk ~~~ from A to B
         moveTower: 2 C B *
             moveTower: 1 C A 
                 moving disk ~ from C to A
             moving disk ~~ from C to B
             moveTower: 1 A B *
                 moving disk ~ from A to B
    
    #include <iostream>
    void toh(int n, char A, char B, char C) {
        if(n == 1) {
            std::cout << "Move Disc 1 from " << A << " to " << C << std::endl;
            return;
        }
        toh(n-1, A, C, B);
        std::cout << "Move Disc " << n << " from " << A << " to " << C <<std::endl;
        toh(n-1, B, A, C);
    }
    int main() {
        int numberOfDisc;
        char A = 'A', B = 'B', C = 'C';
        std::cout << "Enter the number of disc: ";
        std::cin >> numberOfDisc;
        toh(numberOfDisc,  A, B, C);
        return 0;
    }