经典汉诺塔(Java初学递归篇)

在这里插入图片描述


        大一学C的时候已经接触到汉诺塔递归的问题,当时只是简单了解过方法,最近开了算法课,打算重新捋一捋。

题目描述:
        有三根柱子分别为A、B、C,柱子A上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有盘子一个一个移动到柱子C上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方,求解此过程。
在这里插入图片描述
(图片来源:http://www.hannuota.cn/)

        刚拿到题目,我假设n为1,即拿起来放过去即可;假设n为2,先把上面的小盘子拿起放到B,再把下面的大盘子拿起放到C,最后把小盘子拿起放到C;假设n为3…

        当n到5、6的时候,解答就变得困难了。我尝试开始从前面的情况中寻找规律,但好像并不可观…

               汉诺塔小游戏: Tower of Hanoi.
(动手能力强的朋友可以去上面这个网站玩一下模拟的小游戏)

网上检索后发现递归是解这个题目的方法,接着我换了个思路…

        从大的角度想,要把n个盘子移动到目标柱子,是不是要先解决把n-1个盘子移动过去的问题呢?…按这路子一直套娃,解决掉最小子问题即1个盘子的时候,问题似乎好像就可以化繁为简…
                           在这里插入图片描述

按这种思路,很容易就能想到设计这个递归算法的逻辑关键:

(A用From代替表示起点柱子,B用Helper代替表示辅助柱子,C用To代替表示目标柱子)

问题规模为n时*
1、From顶部的n-1个盘子移动到Helper
2、From最底部的大大大盘子移动到To
3、Helper上面的n-1个盘子移动到To
问题规模为n-1时
1、From顶部的(n-1)-1 个盘子移动到Helper
2、From底部的大大盘子移动到To
3、Helper上面的(n-1)-1 个盘子移动到To
问题规模为2时
1、From顶部的 1 个盘子移动到Helper
2、From底部的大盘子移动到To
3、Helper上面的 1 个盘子移动到To

来人!上图(手动起草)
在这里插入图片描述

        这是递归算法的第一个空间栈中计算机所需要做的事情,但并不是三步即可搞定,它会从这个空间中直线引申出许多另外的空间,来解决当前空间的子问题,再一步步回代,当第一个空间中的事情解决了,问题也就解决了。

递归逻辑出来,可以根据其进行码代(分别对应上图3个步骤):

			//对应图中第一步:把n-1个盘子移动到Helper
            Hanoi(n-1, From, Helper, To);
            //对应图中第二步:把最底下的盘子移动到To
            Move(n, From, To);
            //对应图中第三步:把n-1个盘子移动到To
            Hanoi(n-1, Helper, To, From);

然后是递归出口的问题(即n-1为1的时候)

            //出口
            if (n==1) {
    
    
                Move(n,From,To);
                return;
            }

(跑一跑代码,芜湖,迎刃而解~)
在这里插入图片描述

完整的代码:
(Move方法:打印解的步骤)

import java.util.*;

public class Solution {
    
    
        public static void Hanoi(int n,String From,String To ,String Helper) {
    
    
            //出口
            if (n==1) {
    
    
                Move(n,From,To);
                return;
            }
            //对应图中第一步:把n-1个盘子移动到Helper
            Hanoi(n-1, From, Helper, To);
            //对应图中第二步:把最底下的盘子移动到To
            Move(n, From, To);
            //对应图中第三步:把n-1个盘子移动到To
            Hanoi(n-1, Helper, To, From);
        }
        
        public static void Move(int n,String From,String To) {
    
    
            //打印解的步骤
            System.out.println("移动" + n + "号盘子从" + From + "到" + To);
        }
        public static void main(String[] args) {
    
    
            //借助Helper,把5个盘子从From移动到To
            Hanoi(5, "From", "To", "Helper");
        }
}

想起我的数据结构李师之前说的一番话:
        递归代码少,思路对了设计起来也是比较简单,但真正一步步去细想和演算,是非常困难的一件事情,所以把这件事交给计算机,我们做不到的它可以帮我们做到…

(完)

猜你喜欢

转载自blog.csdn.net/weixin_46523794/article/details/115050953