汉诺塔问题 Hanio ——递归思想

问题描述: 一根柱子称原柱上,套有n个盘子,依次从小到大地从上往下地排序着,需要将这n个盘子移动一个目标柱上,要求在移的过程中,大的盘子不可以在小的盘子上面。可以使用一根辅助柱子;

分析: 

    //函数参数:第一个参数表示欲移动的原柱最顶上的n个盘子,第二个参数表示原柱子,第三个参数表示辅助柱子,第三个参数表示目标柱子;

n=1:只有一个盘子: Hanio(1,X,Y,Z) :   X-Z;

n=2:有两个盘子:   Hanio(2,X,Y,Z):       1:X->Y,  2:X->Z, 1:Y->Z;

n=3:有三个盘子时:Hanio(3,X,Y,Z):    1,2:hanio(2,X,Z,Y), 3:X->Z; 1,2:Hanio(2,Y,X,Z);

可见 n=3与n=2是递归关系。

其实n=2与n=1也是递归关系。 Hanio(2,X,Y,Z): 1: Hanio(1,X,Z,Y), 2:X->Z;  1:Hanio(1,Y,X,Z);

具体实现:每个柱子使用一个栈作为数据结构。

为了检测算法移动过程是否违反了”大盘子不可在小盘子之上“规则,

      当n=1:即移动一个盘子时: Hanio(1,X,Y,Z) :  X-Z; 操作中:先判断Z是否为空,若非空,比较当前欲放入元素与Z栈顶元素大小,若前者大,则违反了规则。

 

解决办法:

递归: 将这个问题分解为三个子问题:(1...n):X->Z:

 Hanio(X,Y,Z):划分为:                

a.(1..n-1):X->Y;    Hanio(n-1,X,Z,Y); 

b. (n):X->Z;         

c. (1..n-1):Y->Z;  Hanio(n-1,Y,X,Z);

 

package com.algothrim;

import java.util.Deque;

import java.util.LinkedList;

/*
* 在移动过程中进行检测:如果a要放在b上,对比大小,若b比a小,则打印错误消息,
* 若有错误消息,说明算法实现错误。
*/
public class HanioTemp {
  public void Hanio(int n,Deque<Integer> X,Deque<Integer> Y,Deque<Integer> Z){
  if(n==0) return;
  if(n==1){
           Integer bowl=X.pop();
      if(!Z.isEmpty()){
          Integer ztop=Z.peek();
          if(bowl>ztop) System.out.println("错误:出现大盘子"+bowl+"在小盘子"+ztop+"的情况之上");
       }
       Z.push(bowl);
       return;
    }else{
       Hanio(n-1,X,Z,Y);
      Integer bowl=X.pop();
      Z.push(bowl);
      Hanio(n-1,Y,X,Z);
 }
}
public static void main(String[] args) {
  Deque<Integer> stackX=new LinkedList<Integer>();
  Deque<Integer> stackY=new LinkedList<Integer>();
  Deque<Integer> stackZ=new LinkedList<Integer>();
/*
* satckX初始化:(盘子号越大,表示盘子越大):
* 67,55,23,12,6,3,1
*/
  Integer initArray[]={67,55,23,12,6,3,1};
  int n=initArray.length;
  for(int i=0;i<n;i++){
    stackX.push(initArray[i]);
  }

  System.out.println("移动前:-----------");
  System.out.print("源柱上的盘子共("+stackX.size()+")个:");
  for(int j=n-1;j>=0;j--)
  System.out.print(" "+initArray[j]);
  System.out.println();
  HanioTemp temp=new HanioTemp();
  temp.Hanio(n,stackX,stackY,stackZ);

  System.out.println("移动后:------------");
  System.out.print("源柱上的盘子共("+stackX.size()+")个:");
  while(!stackX.isEmpty())
    System.out.print(" "+stackX.pop());
  System.out.println();

  System.out.print("辅助柱上的盘子共("+stackY.size()+")个:");
  while(!stackY.isEmpty())
    System.out.print(" "+stackY.pop());
  System.out.println();


}

运行结果:

移动前:-----------
源柱上的盘子共(7)个: 1 3 6 12 23 55 67
移动后:------------
源柱上的盘子共(0)个:
辅助柱上的盘子共(0)个:
目标柱上的盘子共(7)个: 1 3 6 12 23 55 67

 

-----------

 递归思想:递归算法(包括直接递归和间接递归子程序)都是通过自己调用自己,将求解问题,划分为性质相同的子问题,最终得到求解的目的。

如何编写递归算法:

通过不完全归纳法,找出递归出口和递归关系。

例:一个楼有n个台阶,有一个人上楼,有时一次跨一个台阶,有时一次跨两个台阶,编写一个算法,计算有几种不同的上楼方法,并分析时间复杂度。

另外的提示:采用函数递归调用的递归法,时间复杂度将是非多项式时间时间,解决:用数学方法解递归关系式,将结果或中间编程结果保存。

 

转载于:https://www.cnblogs.com/dan-cnblogs/p/4731951.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值