传智播客-递归(2)-汉诺塔及程序显示结果改进

来源:互联网 发布:windows managenent 编辑:程序博客网 时间:2024/06/03 06:38

汉诺塔是学习递归的经典问题。

 

有的问题可以用循环解决,也可以用递归,但是汉诺塔问题若采用循环方式来考虑,根本无从下手。汉诺塔问题即:有A,B,C三根柱子,A柱子上有N个盘子,由小至大依次叠放,要将这N个盘子通过辅助柱子B全部转移到C柱子上,转移的过程中依然遵循由小至大的叠放顺序。要求编写一段程序打印出每次移动的过程及总共的移动次数。

 

思考过程:
(个人以为,递归解决这样的问题,第一步主要是采用逆向思考的方式,有个传说中的问题,海盗分钻石的故事,据说是MS的智力考试题,解决思路就是采用的逆向思维,在这里,简单地说,就是倒推)

 

最后一步的现况,肯定是第N个盘子留在A柱子,其余的都在B柱子上,然后先将A柱子上的盘子移动到C,再把B上的盘子全部转移过来--这个最后一步,是单指从C柱子上叠放盘子顺序的最后一步(即只关注单个柱子叠放盘子的过程,没有考虑ABC三个柱子之间盘子转移的过程),这个是倒推。

 

然后采用递归的思考要点(1)将一个大问题分解为有限多个同质的小问题,但是暂不考虑小问题的具体处理细节和过程(详情请参见上一篇),这样的话,其实上面所讲的“最后一步”,就可以理解为“第N步”,因为每一个盘子由大至小依次转移到C柱子上的时候,过程都是一样的,或者说,同质的。那么,“第N步”,就又可以理解为“每一步”了,这样,第一个小问题就抽取出来了。

 

然后,对上面的“每一步”再细分,还是采用递归思考要点(1),先再分成有限多个小问题,不过这次要关注ABC之间盘子转移的过程了。
(1)将A上的第N个盘子放到C上,从这一步抽取的方法设为moveOne(int Nth, String to),Nth是指第N个盘子,to是指C。
(2)将B上的N-1个盘子放到C上,此时肯定以A为辅助柱子,这一步的方法可以设为moveAll(int total, String from, String mid, String to ),total是N-1,from是B,mid是A,to是C。

 

问题还没完。

 

需要再往上回溯一步。(3)A盘子上的N-1个盘子如何移到B上的呢?显然是以C为辅助转移过去的。这一步仍然采用moveAll方法,total是N-1,from是A,mid是C,to是B。(因为整个过程是以A为起点,C为终点,所以这一步是必须考虑的)

 

这样,将N个盘子从A借助B转移到C的过程就可以分解为上述三个步骤,顺序为(3)-(1)-(2)。而程序的起点是moveAll(int N, String “A”, String “B”, String to “C”),然后在这个程序中依次调用上述三个方法。

 

至于移动的总次数,只要统计moveOne的调用次数就可以了。因为实际的移动是由这个方法产生的。

 

移动的具体过程显示有三种方式:
(1)在moveOne方法里加一条打印语句。
(2)将ABC三个柱子的盘子数存放在三个相应的列表里,然后再将柱子和对应的列表存放到一个map里面。然后再写一个showAll方法打印出每个列表的数据。每调用一次moveOne,就更改一次ABC列表的数据,然后调用showAll方法。
(3)如下图所示:有三条并排的涌道,分别代表ABC三个柱子,对应(2)里面的三个列表。涌道用竖线“|”表示,盘子用减号“-”表示,为了美观,第N个盘子用2N个“-”表示。则涌道的高度为盘子数N,每个涌道的宽度为2N。

 

代码设计思路:
1、每调用一次showOne就打印一次三个涌道,还是showAll方法。
2、打印的顺序是先水平再垂直,则垂直方向的代码表示可以设为for(i<N),然后在这个for循环里打印每一行的结果。
3、水平方向,涌道的间隔“|”是固定的,四个,每两个中间打印相应的盘子数,有的话均(表现出)居中打印,没有则为空。
4、打印盘子的代码可以单独设立一个(咳咳。。用专业的说法,就是方法的封装),定为showLine(int theN),theN表示为该柱子(列表)中的第几个盘子。(个人以为这段图形显示代码的难点就在这个theN的处理上。)
5、从图中可以看出,每少一个盘子,涌道左右就各多一个空格(因为2个减号表示一个盘子,相应的,2个空格就表示缺失的一个盘子),因此,从左至右打印的顺序是,先打印N-theN个空格,再打印2theN个减号,再打印N-theN个空格。

hanoi3

 

下面是(2)的代码(下面的showAll方法为protected,是因为我写Hanoi3继承该类时复写了这个方法):
public class Hanoi2 {
 protected static int count = 0;
 protected Integer total = 0;
 protected List<Integer> aList = new ArrayList<Integer>();
 protected List<Integer> bList = new ArrayList<Integer>();
 protected List<Integer> cList = new ArrayList<Integer>();
 protected static HashMap<String, List<Integer>> map = new HashMap<String, List<Integer>>();
 
 public Hanoi2(){}
 
 public Hanoi2(Integer total){
  this.total = total;
  for(int i = 1; i <= total; i++){
   aList.add(i);   
  }
  map.put("A", aList);
  map.put("B", bList);
  map.put("C", cList);
 }
 
 public void startMove(){
  showAll();
  moveAll(total, "A", "B", "C");
 }
 
 protected void showAll(){
  System.out.println("A: " + map.get("A"));
  System.out.println("B: " + map.get("B"));
  System.out.println("C: " + map.get("C"));
 }

 private void moveAll(int total, String from, String mid, String to){
  
  if ( total == 1){
   moveOne(total, from, to);
  }else{
   moveAll(total - 1, from, to, mid);
   moveOne(total, from, to);
   moveAll(total - 1, mid, from, to);
  }
 }
 
 private void moveOne(int theN, String from, String to){
  map.get(to).add(0, map.get(from).remove(0));
  System.out.println("move the " + theN + "th from " + from + " to " + to);
  count++;
  showAll();
 }
 
 public int getCount(){
  return count;
 }
 
 public static void main(String[] args) {
  Hanoi2 hanoi = new Hanoi2(3);
  hanoi.startMove();
  System.out.println(hanoi.getCount());
 }
}

第(3)个方法,theN数值的处理算法为:
int n = 0;
if(i >= total - aList.size()) { //确认队列里有盘子了,或者说确认,到了队列里开始存放盘子的位置了
 n = (Integer)aList.get(i - (total - aList.size())); //从开始存放盘子的位置起重新计算取盘子的下标值
}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淋浴房一边是窗怎么办 1岁宝宝让狗咬了怎么办 2岁宝宝让狗咬了怎么办 带4个小孩只买两张儿童票怎么办 墙面补漆颜色有色差怎么办 墙壁刷的乳胶漆颜色不满意怎么办 门被水泡的鼓了怎么办 定制衣柜做大了怎么办 找平的地面高了怎么办 卫生间推拉门锁坏了怎么办 阳台推拉门框安装斜了怎么办? 电子门钥匙坏了怎么办 门的保险锁坏了怎么办 小区楼宇门坏了怎么办 门的锁坏了怎么办 汽车门把锁坏了怎么办 厨柜门上的板板掉了怎么办 衣柜门滑轮坏了怎么办 厨房推拉门推动时有声音是怎么办? 塑料推拉门声音大怎么办不好推 推拉门锁扣坏了怎么办 衣柜移门拉不动怎么办?如何保养 擦黑色桌面有层白灰怎么办 宝宝睡觉不盖被子怎么办 孩子盖被子就哭怎么办 一盖被子就发烧怎么办 两岁宝宝认被子盖怎么办 小孩吃多了发烧怎么办 两岁宝宝拉蛔虫怎么办 吃了长蛆的东西怎么办 被蜱虫咬了又找不到虫子怎么办 木家具生黑虫子怎么办 吃了发霉的面包怎么办 种的韭菜有蛆怎么办 活狗身上长蛆虫怎么办 狗身上会有蛆虫怎么办 狗身上长满了蛆怎么办 房间墙上有很多小虫子怎么办 床上有许多小虫子怎么办? 店里有许多小虫子怎么办 房间潮湿有很多小虫子怎么办