您的位置:

Java实现汉诺塔算法

一、什么是汉诺塔?

汉诺塔是一种数学问题,同时也是一种益智游戏。其规则如下:

将所有的盘子从起点柱子移动到目标柱子,每次只能移动一个盘子,并且大盘子不能放在小盘子上面。起始柱子上的盘子按大小顺序由下到上依次编号为1至n,目标柱子上无盘子。


二、算法思路

假设有三个柱子分别为A、B、C,现在要从A柱子上将n个盘子移至C柱子,那么汉诺塔算法的解题步骤如下:

Step1: 将A柱子上编号为1至n-1的盘子移动至B柱子,此时空出A柱子的最底下一个盘子。

Step2: 将A柱子上编号为n的盘子移动至C柱子,此时A柱子上无盘子。

Step3: 将B柱子上编号为1至n-1的盘子移动至C柱子,此时汉诺塔游戏成功结束。

以上便是汉诺塔问题求解的递归思路。接下来,我们将这个思路用Java语言实现。


三、Java代码实现

public class HanoiTower {
    public static void hanoi(int n, char A, char B, char C) {
        if (n == 1) {//递归出口:只有一个盘子的情况
            System.out.println(A + "->" + C);
            return;
        }
        hanoi(n - 1, A, C, B);//Step1
        System.out.println(A + "->" + C);//Step2
        hanoi(n - 1, B, A, C);//Step3
    }
    public static void main(String[] args) {
        int n = 3;//汉诺塔的盘子数量
        hanoi(n, 'A', 'B', 'C');
    }
}

四、程序演示

运行上述代码,可以得到如下输出结果:

A->C

A->B

C->B

A->C

B->A

B->C

A->C


五、优化思路

当盘子数较大时,递归代码的执行效率较低。为了提高程序的效率,可以使用非递归方式实现汉诺塔算法。具体方法为:

Step1: 直接将A柱子上编号为1至n的盘子移动至C柱子,此时A柱子上无盘子,B柱子是备用柱子。

Step2: 当n为奇数时,将B柱子作为中间柱子,依次将C柱子上编号为1至n的奇数盘子(从C柱子底部开始)移动至B柱子,再将A柱子上编号为1至n的偶数盘子依次移动至C柱子,最后将B柱子上的所有盘子依次移动至C柱子。当n为偶数时,将A柱子作为中间柱子,重复以上操作。

以上方法可以通过栈数据结构实现,具体实现方式可参考下方代码:

import java.util.Stack;

public class HanoiTower {
    static Stack s1 = new Stack<>();//表示A柱子
    static Stack
    s2 = new Stack<>();//表示B柱子
    static Stack
     s3 = new Stack<>();//表示C柱子
    
    public static void main(String[] args) {
        int n = 3;//汉诺塔的盘子数量
        for (int i = n; i >= 1; i--) {
            s1.push(i);//向A柱子中压入n个圆盘
        }
        hanoi(n);//移动n个盘子
    }

    public static void hanoi(int n) {
        int from = 1;//表示起始塔
        int to = 3;//表示目标塔
        if (n % 2 == 0) {
            to = 2;//当n为偶数时,将B柱子作为中间柱子
        }
        int mid = 6 - from - to;//表示中间塔
        int count = 0;//用于计数
        boolean isUp = true;//用于表示弹出的盘子是否向上
        while (s3.size() < n) {//当C柱子上的盘子数量不足n时
            if (isUp) {//弹出A或B柱子的栈顶元素向上
                int x;
                if (!s1.empty() && (s2.empty() || s1.peek() < s2.peek())) {
                    x = s1.pop();//从A柱子弹出元素
                    System.out.println("Move " + x + " from " + from + " to " + to);
                    s2.push(x);//将元素压入B柱子
                    if (s3.size() == n) {//当圆盘全部移动到C柱子上时,退出循环
                        break;
                    }
                } else if (!s2.empty() && (s1.empty() || s2.peek() < s1.peek())) {
                    x = s2.pop();//从B柱子弹出元素
                    System.out.println("Move " + x + " from " + (from + 1) % 3 + " to " + to);
                    s1.push(x);//将元素压入A柱子
                    if (s3.size() == n) {//当圆盘全部移动到C柱子上时,退出循环
                        break;
                    }
                }
                count++;//计数器加1
                if (count == n) {//当计数器值为n时,改变弹出元素的方向
                    isUp = false;
                }
            } else {//弹出C柱子的栈顶元素向下
                int x;
                if (!s1.empty() && (s3.empty() || s1.peek() < s3.peek())) {
                    x = s1.pop();//从A柱子弹出元素
                    System.out.println("Move " + x + " from " + from + " to " + mid);
                    s3.push(x);//将元素压入C柱子
                } else if (!s3.empty() && (s1.empty() || s3.peek() < s1.peek())) {
                    x = s3.pop();//从C柱子弹出元素
                    System.out.println("Move " + x + " from " + to + " to " + from);
                    s1.push(x);//将元素压入A柱子
                }
                count--;//计数器减1
            }
        }
    }
}

    
   
  

六、总结

汉诺塔算法作为一种数学问题和益智游戏,可以启发人们思考和锻炼逻辑思维能力。在Java语言中,汉诺塔算法可以通过递归和非递归方式实现,并且非递归方式能够有效提高程序的执行效率。