用c语言实现汉诺塔问题的递归函数编程

一.汉诺塔问题

汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着 6464 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘,如图所示:
在这里插入图片描述
现在请试着编写一个程序,对于一个有 nn 个盘子的汉诺塔,列举将这 nn 个盘子从柱子 A 移动到柱子 C 需要的所有移动步骤,每个步骤占一行。例如,将一个盘子从 A 移动到 C,即表示为:
A–>C

二.代码实现和分析

先直接上代码:

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
/*汉诺塔的递归函数实现*/
int hanoi(int n,char base,char target,char medium)
{
    
    
    if(n == 1)
    {
    
    
        cout << base << "->" << target << endl;  //只有一个的时候,直接
        return 0;                                //将所在位置拿到目标位
    }             								 //置
    else
    {
    
    
        hanoi(n - 1, base, medium, target);      //有多个盘子时就先将最
        								   //底层盘子的上面n-1个挪到中介
    }									//也就是需要挪动n-1块 到中介
    cout << base << "->" << target << endl;//n-1个挪完后将最底层的挪到目标
    if(n == 1)
    {
    
    
        cout << base << "->" << target << endl;
        return 0;
    }
    else
    {
    
    
        hanoi(n - 1, medium, target, base);//上面n-1块挪到中介完成后,需要再将中介上的n-1块在挪回到目标上   
        return 0; //n-1块挪到目标上后此次调用就完成
    }
}
int main() {
    
    
    int n;
    char A='A', B='B', C='C';
    scanf("%d",&n);
    hanoi(n, A, B, C);

    return 0;
}

三.问题分析

先分析一下这个问题的解决方法,
先从2块和3块来看看移动的操作,然后归纳总结一下一般步骤,有没有什么规律可循。
当有2块时:
A->B
A->C
B->C
当有3块时:
A->C
A->B
C->B
A->C
B->A
B->C
A->C

从这两个移动步骤可以看到,都是先将n-1块移动到中介的那块杆上,再将最后一块最大的移动到目标杆上,然后再将n-1块移动到目标位置上;

而再将n-1块移动到中介杆上时也可以将它看做先将n-2块移动到目标杆上,在将第n-1块移动到中介杆上,最后再将n-2块移回到中介杆上。

所有过程都可以分为以上三个步骤;

递归终止的条件就是当n==1时,直接将当前的盘子放进目标盘;

可以看出,不管是将n-1块移动到中介位置,还是再将n-1块移回到目标位置,都是从一根杆移动到另一跟杆,所以这两种操作可以用同一个函数表示,这边也可以得到一个移动步骤数的关系:移动n块从一根杆到另一跟杆需要的操作步骤数等于移动n-1块操作步骤数(假设为x)的2x+1;

因为这里并没有真正的操作只是让输出需要的操作,所以我们可以用输出打印来代替已经移动了的操作;

因为上面的三个步骤,第一和第二其实都是一样的将盘子从一个轴移动到另一个轴,不同的是当前的轴和目标轴不同,所以每次调用自身函数迭代时需要更改的也就是当前轴,目标轴和

第一次调用:
移动n块到目标轴时,先将n-1块移动到中介轴,这里为了迭代就需要在调用迭代时将n块的中介轴变为n-1块的目标轴;

hanoi(n - 1, base, medium, target); 

第二次调用:
将n-1块移动到n块的中介轴上后,再将n-1块移动回n块的目标轴,这个时候当前轴变为了n块中介轴,所以这里为了迭代就需要在调用迭代时将n块的中介轴变为n-1块的当前轴;

hanoi(n - 1, medium, target, base);

如果是人手动来计算操作步骤,根据盘子的数量和迭代的终止条件可知道,第一盘子应该放在目标轴还是中介轴上,如果是奇数就放在目标轴上,如果是偶数就放在中介轴上,第二块就放在另一轴上,再将前一块放在第二块轴上,这就将两块放在了一个轴上,然后再将当前轴上的一块放在空出来了的那个轴上,再将那两块在同一轴上的盘子按照刚才放在一根轴上的步骤再重新操作放在刚放了一个盘子的轴上,后面就按上述操作不断的将三块放在另一个轴上空出一个轴,从当前轴取出一个放在空轴上,再将三块放在其上形式四个盘子的轴,空出一个轴,从当前轴取出一个放在空轴上,再将四块放在其上形式五个盘子的轴,空出一个轴。。。。

猜你喜欢

转载自blog.csdn.net/weixin_42224577/article/details/109071706