史上最全!详解java递归解决汉诺塔问题

引子

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。


提示:以下是本篇文章正文内容,下面案例可供参考

一、解题思路

说简单点:就是把A上的n个圆盘全部移到C上,要求是,操作过程中ABC三个柱子从下往上,盘子依然是从大到小
在这里插入图片描述
我们先来看几种简单的情况:
n=1时:
A上只有1个圆盘,你直接移到C即可,我们用A->C表示
n=2时:
A上2个圆盘,我们把最上面的移动到B,然后A剩余1个圆盘,,再把A剩余圆盘移动到C,最后B移动到C,我们用A->B,A->C,B->C表示,如下图:

在这里插入图片描述
A->B
在这里插入图片描述
A->C
在这里插入图片描述
B->C
在这里插入图片描述
到这里完成n=2的目标。

n=3时:
示意图如下:
在这里插入图片描述
A->C
在这里插入图片描述
A->B
在这里插入图片描述
C->B
在这里插入图片描述
A->C
在这里插入图片描述
B->A
在这里插入图片描述
B->C
在这里插入图片描述
A->C
在这里插入图片描述
到这里n=3移植完毕。
注意
在n=3时,我们可以发现,要从A移动3个盘子到C上,我们会经历2个盘子在B上的时候,如下图:
在这里插入图片描述
因为C上已经有最大的盘了,那这个时候问题就变成了,如何把B上2个盘子移动到C上,那不就是n=2时的操作吗?只不过这时B成了出发站,A成了中转站,C仍是目标站

我们用这个思路来看一看n=4的情况
在这里插入图片描述
我们想办法把最大盘移动到C,然后剩余3个盘依次移动到B,如上图。这时问题就转换成了,如何把三个盘子从下往上是从大到小的顺序移动到C,这时思路就和n=3一样了

至此,递归的思路就很清晰了:n个盘子的时候,将n-1个盘子移动到中转上,然后从起始位置把1个最大盘移动到目标位置上。

然后问题转换为:中转位置成为起始位置,原起始位置成为中转位置,目标位置仍是pos3,如何把起始位置上n-2个盘子移动到目标位置上?
。。。

二、实战代码

代码如下(示例):

public static void move(char pos1 ,char pos2) {
    
    
        //模拟实现盘子的移动
        //pos1移动到pos2,这里pos1、pos2只是一个代指
        // 比如你想移动A上方的一个盘子到C,你传参就是pos1=A,pos2=B
        System.out.print(pos1+"->"+pos2+" ");
    }

    public static void hanNuoTa(int n,char pos1 ,char pos2,char pos3) {
    
    
        //n表示要移动的盘子个数
        //pos1起始位置、pos2中转位置、pos3目标位置
        //因为移动过程中,目标位置、中转位置是会变的
        if(n==1)
        {
    
    
            move(pos1,pos3);
        }
        else
        {
    
    
            hanNuoTa(n-1,pos1,pos3,pos2);
            //起始位置移动n-1个到中转位置
            move(pos1,pos3);//n-1个移动完,将起始位置最大的1个移动到目标位置
            //问题转换成:pos2是起始位置,pos3目标位置,pos1中转位置,如何将n-1个盘,从pos2移动到pos3
            hanNuoTa(n-1,pos2,pos1,pos3);
        }
    }

    public static void main(String[] args) {
    
    
        hanNuoTa(1,'A','B','C');
        System.out.println();
        hanNuoTa(2,'A','B','C');
        System.out.println();
        hanNuoTa(3,'A','B','C');
        System.out.println();
        hanNuoTa(4,'A','B','C');
        System.out.println();
    }

关于下面代码的解释:

public static void hanNuoTa(int n,char pos1 ,char pos2,char pos3) {
    
    
        //n表示要移动的盘子个数
        //pos1起始位置、pos2中转位置、pos3目标位置
        //因为移动过程中,目标位置、中转位置是会变的
        if(n==1)
        {
    
    
            move(pos1,pos3);
        }
        else
        {
    
    
            hanNuoTa(n-1,pos1,pos3,pos2);
            //起始位置移动n-1个到中转位置
            move(pos1,pos3);//n-1个移动完,将起始位置最大的1个移动到目标位置
            //问题转换成:pos2是起始位置,pos3目标位置,pos1中转位置,如何将n-1个盘,从pos2移动到pos3
            hanNuoTa(n-1,pos2,pos1,pos3);

我们要从pos1移动n个盘去pos3,得先移动n-1个去pos2,全移动完后剩下一个大盘在pos1,我们移动到pos3;然后我们把pos2上的n-1个盘全移动到pos3即可完成
几组测试示例如下:
在这里插入图片描述


总结

汉诺塔问题理清脉络就是一个递归问题,上述方法设盘子数为n, n可为任意数,该法同样适用于移动n-1个盘。因此,依据上法,可解决n -1个盘子从A杆移到B杆(第一步)或从B杆移到C杆(第三步)问题。现在,问题由移动n个盘子的操作转化为移动n-2个盘子的操作。依据该原理,层层递推,即可将原问题转化为解决移动n -2、n -3… … 3、2,直到移动1个盘的操作,而移动一个盘的操作是可以直接完成的。

猜你喜欢

转载自blog.csdn.net/m0_57180439/article/details/120972175
今日推荐