博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
汉诺塔问题 Hanio ——递归思想
阅读量:4966 次
发布时间:2019-06-12

本文共 2622 字,大约阅读时间需要 8 分钟。

问题描述: 一根柱子称原柱上,套有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

你可能感兴趣的文章
JRebel安装部署,激活
查看>>
OPENSSL使用方法
查看>>
下载GO的开源开发工具LITEIDE
查看>>
接口操作XML
查看>>
idhttp访问DATASNAP有密码验证的中间件
查看>>
libmidas.so.2
查看>>
开发WINDOWS服务程序
查看>>
httpencode编码
查看>>
cross socket和msgpack的数据序列和还原
查看>>
解决跨操作系统平台JSON中文乱码问题
查看>>
DELPHI搭建centos开发环境
查看>>
IdHTTPServer允许跨域访问
查看>>
DELPHI开发LINUX包
查看>>
更新.net core 3.0,dotnet ef命令无法使用的解决办法
查看>>
React躬行记(13)——React Router
查看>>
前端利器躬行记(1)——npm
查看>>
前端利器躬行记(2)——Babel
查看>>
前端利器躬行记(3)——webpack基础
查看>>
前端利器躬行记(4)——webpack进阶
查看>>
前端利器躬行记(5)——Git
查看>>