汉诺塔Java递归和非递归算法解析

汉诺塔Java递归和非递归算法解析

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

这是一个典型的递归调用算法,要实现把n个圆盘从A移到C,我们只需要做到如下三步:

①:把n-1个圆盘从A移到B

②:把A最底层的圆盘从A移到C

③:把B上的n-1个圆盘移到C。

public class Hanio递归 {
    
    
    static int i = 1;
    public static void main(String[] args) {
    
    
        Hanoi(3,"A","B","C");
    }
    public static void Hanoi(int num,String a,String b,String c){
    
    
        if (num ==1 ){
    
    
            System.out.println ("第  "+i+"  次移动,把编号为  1  的圆盘从  "+a+"   移动到  "+c);
            i++;
        }
        else {
    
    
            Hanoi(num - 1, a, c, b);
            // 将起始柱上剩余的最后一个大圆盘移动到目标柱上
            System.out.println("第  "+i+"  次移动,把编号为  "+num+"  的圆盘从  "+a+"   移动到  "+c);
            i++;
            // 递归调用 hanoi() 函数,将辅助柱上的 num-1 圆盘移动到目标柱上
            Hanoi(num - 1, b, a, c);
        }
    }
}

Hanoi他问题的递归算法时间复杂度是O(2^n),而且递归算法调用空间是很大的,代码难写但简洁,计算机非常难受。

那么非递归算法该怎么实现呢

最简单的就是用栈模拟递归

import java.util.Stack;

public class Hanoi非递归 {
    
    
    public static void main(String[] args) {
    
    
        Hanoi("A","B","C",3);
    }
    public static void Hanoi(String a,String b,String c,int num){
    
    
        Stack<State> starks = new Stack<> ();
        State state = new State(a,b,c,num,false);
        starks.push (state);
        while (starks.size ()>0){
    
    
            if(starks.peek ().title){
    
    
                HanoiPrint(starks.pop ());
            }
            else {
    
    
                State NumLinShi=starks.pop ();
                if (NumLinShi.Num==1){
    
    
                    HanoiPrint(NumLinShi);
                }
                else {
    
    
                    State NumLinA_B = new State (NumLinShi.A,NumLinShi.C,NumLinShi.B,NumLinShi.Num-1,false);
                    State NumLinA_C = new State (NumLinShi.A,NumLinShi.B,NumLinShi.C,NumLinShi.Num,true);
                    State NumLinB_C = new State (NumLinShi.B,NumLinShi.A,NumLinShi.C,NumLinShi.Num-1,false);
                    starks.push (NumLinB_C);
                    starks.push (NumLinA_C);
                    starks.push (NumLinA_B);
                }
            }
        }
    }
    public static void HanoiPrint(State str){
    
    
        System.out.println ("把编号为\t"+str.Num+"\t的圆盘从\t"+str.A+"\t移动到\t"+str.C+"\t盘子上");
    }
}
class State {
    
    
    public String A;
    public String B;
    public String C;
    public int Num;
    public boolean title;
    public State(String A, String B, String C , int Num,boolean title)
    {
    
    
        this.A = A;
        this.B = B;
        this.C = C;
        this.Num = Num;
        this.title = title;
    }
}

先定义一个类名叫State,State有属性A,B,C,Num,title,A就是盘子的移动杆,B就是中间杆,C就是盘子的接受杆,Num就是被移动的盘子编号,title是一个标记,当title=true时表示该对象可以输出了。

这个代码的核心是Hanoi非递归类中的Hanoi方法,我们来拆解这个方法。

首先定义一个栈,把原始数据存入

Stack<State> starks = new Stack<> ();
        State state = new State(a,b,c,num,false);

之后如果栈顶元素的Num=1,那就是只有一个盘子了就直接输出,

扫描二维码关注公众号,回复: 14613830 查看本文章

否则把栈顶元素按照如下规则一化三,栈顶元素出栈,以下三个元素进栈

①:把n-1个圆盘从A移到B

②:把A最底层的圆盘从A移到C

③:把B上的n-1个圆盘移到C。

while (starks.size ()>0){
    
    
    if(starks.peek ().title){
    
    
        HanoiPrint(starks.pop ());
    }
    else {
    
    
        State NumLinShi=starks.pop ();
        if (NumLinShi.Num==1){
    
    
            HanoiPrint(NumLinShi);
        }
        else {
    
    
            State NumLinA_B = new State (NumLinShi.A,NumLinShi.C,NumLinShi.B,NumLinShi.Num-1,false);
            State NumLinA_C = new State (NumLinShi.A,NumLinShi.B,NumLinShi.C,NumLinShi.Num,true);
            State NumLinB_C = new State (NumLinShi.B,NumLinShi.A,NumLinShi.C,NumLinShi.Num-1,false);
            starks.push (NumLinB_C);
            starks.push (NumLinA_C);
            starks.push (NumLinA_B);
        }
    }
}
   starks.push (NumLinB_C);
        starks.push (NumLinA_C);
        starks.push (NumLinA_B);
    }
}

}
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_55534317/article/details/123558172