OOP00-递归函数-汉诺塔(Tower of Hanoi)问题

OOP00-递归函数-汉诺塔(Tower of Hanoi)问题

思路

找到规律, 化繁为简, 分而治之.

问题描述

  • 基本情况
    汉诺塔有3个柱子, 分别为pillar1, pillar2, pillar3.
    在柱子上套着大小不一的盘子, 用数字1,2,3等表示盘子的大小, 数字大的盘子大.
  • 约束条件
    小的盘子只能套在大的盘子的上面.
  • 初始状态
    开始状态是所有的盘子都套在柱子pillar1上, 这里假设有6个盘子(只是为了降低输出结果的数量, 原始的故事中有64个盘子).
  • 目标状态
    目标状态是所有的盘子都套在柱子pillar3上.
  • 动作约束
    每次只能移动一个柱子的最上面的1个盘子到另一个柱子.
  • 可用资源
    可以用pillar2作为中转站. 没有其他可暂存的空间.
  • 需要回答的疑问
    描述移动盘子的过程和需要的移动次数.

问题分析

从小规模的问题开始, 逐渐增加问题的规模.
从人工完成问题的求解开始, 找到规律后, 再用程序自动化完成问题求解.
下面的结果示例中, 表示盘子的数字序列的左侧表示柱子的底部, 例如pillar1: [3, 2, 1].
1个盘子, 移动1次完成

pillar1: [1]                    pillar2: []                     pillar3: []                     
pillar1: []                     pillar2: []                     pillar3: [1]                    

2个盘子,移动3次完成.

pillar1: [2, 1]                 pillar2: []                     pillar3: []                     
pillar1: [2]                    pillar2: [1]                    pillar3: []                     
pillar1: []                     pillar2: [1]                    pillar3: [2]                    
pillar1: []                     pillar2: []                     pillar3: [2, 1]                 

3个盘子,移动7次完成

pillar1: [3, 2, 1]              pillar2: []                     pillar3: []                     
pillar1: [3, 2]                 pillar2: []                     pillar3: [1]                    
pillar1: [3]                    pillar2: [2]                    pillar3: [1]                    
pillar1: [3]                    pillar2: [2, 1]                 pillar3: []                     
pillar1: []                     pillar2: [2, 1]                 pillar3: [3]                    
pillar1: [1]                    pillar2: [2]                    pillar3: [3]                    
pillar1: [1]                    pillar2: []                     pillar3: [3, 2]                 
pillar1: []                     pillar2: []                     pillar3: [3, 2, 1]              

4个盘子, 移动15次完成

pillarFrom: [4, 3, 2, 1]        pillarB: []                     pillarTo: []                    
pillarFrom: [4, 3, 2]           pillarB: [1]                    pillarTo: []                    
pillarFrom: [4, 3]              pillarB: [1]                    pillarTo: [2]                   
pillarFrom: [4, 3]              pillarB: []                     pillarTo: [2, 1]                
pillarFrom: [4]                 pillarB: [3]                    pillarTo: [2, 1]                
pillarFrom: [4, 1]              pillarB: [3]                    pillarTo: [2]                   
pillarFrom: [4, 1]              pillarB: [3, 2]                 pillarTo: []                    
pillarFrom: [4]                 pillarB: [3, 2, 1]              pillarTo: []                    
pillarFrom: []                  pillarB: [3, 2, 1]              pillarTo: [4]                   
pillarFrom: []                  pillarB: [3, 2]                 pillarTo: [4, 1]                
pillarFrom: [2]                 pillarB: [3]                    pillarTo: [4, 1]                
pillarFrom: [2, 1]              pillarB: [3]                    pillarTo: [4]                   
pillarFrom: [2, 1]              pillarB: []                     pillarTo: [4, 3]                
pillarFrom: [2]                 pillarB: [1]                    pillarTo: [4, 3]                
pillarFrom: []                  pillarB: [1]                    pillarTo: [4, 3, 2]             
pillarFrom: []                  pillarB: []                     pillarTo: [4, 3, 2, 1]   

观察中的发现

要把k个盘子从pilla1, 移动到pilla3,
如果只有1个盘子, k=1时, 只需要

  • 盘子从pilla1, 移动到pilla3上.

如果有k个盘子, k>1时, 需要

  • 先把pilla1上的前k-1个盘子移动到pilla2上
    • 可以用pilla3作为中转站.
    • 问题得到简化, 比原来的问题少1个盘子.
  • 然后, 把第k个盘子从pilla1, 移动到pilla3上.
  • 然后, 把pilla2上的k-1个盘子移动到pilla3上
    • 可以用pilla3作为中转站.
    • 问题得到简化, 比原来的问题少1个盘子.

这样就把移动k个盘子的问题, 分解为2个移动k-1个盘子(问题变简单一些)和1次肯定能完成的移动(第k个盘从pilla1, 移动到pilla3上).

根据上面的规律编写程序.

编写Java程序

import java.util.Stack;

public class HanoiTower {

    static long counter = 0;
    static Stack pillarFrom = new Stack();
    static Stack pillarB = new Stack();
    static Stack pillarTo = new Stack();

    public static void hanoi(Stack pillar1, Stack pillar2, Stack pillar3, int moveAmount) {
        if (moveAmount == 1) {
            pillar3.push(pillar1.pop());
            counter++;
            printPillars();
        } else {
            hanoi(pillar1, pillar3, pillar2, moveAmount - 1);
            pillar3.push(pillar1.pop());
            counter++;
            printPillars();
            hanoi(pillar2, pillar1, pillar3, moveAmount - 1);
        }
    }

    public static void main(String[] args) {
        int amount = 6;
        for (int i = 0; i < amount; i++) {
            pillarFrom.push(amount - i);
        }
        printPillars();
        hanoi(pillarFrom, pillarB, pillarTo, amount);
        System.out.println("counter = " + counter);
    }

    public static void printPillars() {
        System.out.printf(String.format("%-32s", "pillar1: " + pillarFrom.toString()));
        System.out.print(String.format("%-32s", "pillar2: " + pillarB.toString()));
        System.out.println(String.format("%-32s", "pillar3: " + pillarTo.toString()));
    }
}

说明:
由于只能从最上面拿走1个盘子, pillar1, pillar2, pillar3用堆栈实现, 分别用静态变量pillarFrom, pillarB, pillarTo表示pillar1, pillar2, pillar3.
hanoi(Stack pillar1, Stack pillar2, Stack pillar3, int moveAmount)中的参数 pillar1, pillar2, pillar3在首次调用时表示 最初问题的pillar1, pillar2, pillar3; 在进行递归调用后, 表示在问题简化后的, 即由移动k个盘子的问题转化为移动k-1个盘子问题后的柱子 pillar1, pillar2, pillar3.
String.format("%-32s", "pillar1: " + pillarFrom.toString()) 是把字符串格式化为32个字符, 为了显示美观.

运行输出

pillar1: [6, 5, 4, 3, 2, 1]     pillar2: []                     pillar3: []                     
pillar1: [6, 5, 4, 3, 2]        pillar2: [1]                    pillar3: []                     
pillar1: [6, 5, 4, 3]           pillar2: [1]                    pillar3: [2]                    
pillar1: [6, 5, 4, 3]           pillar2: []                     pillar3: [2, 1]                 
pillar1: [6, 5, 4]              pillar2: [3]                    pillar3: [2, 1]                 
pillar1: [6, 5, 4, 1]           pillar2: [3]                    pillar3: [2]                    
pillar1: [6, 5, 4, 1]           pillar2: [3, 2]                 pillar3: []                     
pillar1: [6, 5, 4]              pillar2: [3, 2, 1]              pillar3: []                     
pillar1: [6, 5]                 pillar2: [3, 2, 1]              pillar3: [4]                    
pillar1: [6, 5]                 pillar2: [3, 2]                 pillar3: [4, 1]                 
pillar1: [6, 5, 2]              pillar2: [3]                    pillar3: [4, 1]                 
pillar1: [6, 5, 2, 1]           pillar2: [3]                    pillar3: [4]                    
pillar1: [6, 5, 2, 1]           pillar2: []                     pillar3: [4, 3]                 
pillar1: [6, 5, 2]              pillar2: [1]                    pillar3: [4, 3]                 
pillar1: [6, 5]                 pillar2: [1]                    pillar3: [4, 3, 2]              
pillar1: [6, 5]                 pillar2: []                     pillar3: [4, 3, 2, 1]           
pillar1: [6]                    pillar2: [5]                    pillar3: [4, 3, 2, 1]           
pillar1: [6, 1]                 pillar2: [5]                    pillar3: [4, 3, 2]              
pillar1: [6, 1]                 pillar2: [5, 2]                 pillar3: [4, 3]                 
pillar1: [6]                    pillar2: [5, 2, 1]              pillar3: [4, 3]                 
pillar1: [6, 3]                 pillar2: [5, 2, 1]              pillar3: [4]                    
pillar1: [6, 3]                 pillar2: [5, 2]                 pillar3: [4, 1]                 
pillar1: [6, 3, 2]              pillar2: [5]                    pillar3: [4, 1]                 
pillar1: [6, 3, 2, 1]           pillar2: [5]                    pillar3: [4]                    
pillar1: [6, 3, 2, 1]           pillar2: [5, 4]                 pillar3: []                     
pillar1: [6, 3, 2]              pillar2: [5, 4, 1]              pillar3: []                     
pillar1: [6, 3]                 pillar2: [5, 4, 1]              pillar3: [2]                    
pillar1: [6, 3]                 pillar2: [5, 4]                 pillar3: [2, 1]                 
pillar1: [6]                    pillar2: [5, 4, 3]              pillar3: [2, 1]                 
pillar1: [6, 1]                 pillar2: [5, 4, 3]              pillar3: [2]                    
pillar1: [6, 1]                 pillar2: [5, 4, 3, 2]           pillar3: []                     
pillar1: [6]                    pillar2: [5, 4, 3, 2, 1]        pillar3: []                     
pillar1: []                     pillar2: [5, 4, 3, 2, 1]        pillar3: [6]                    
pillar1: []                     pillar2: [5, 4, 3, 2]           pillar3: [6, 1]                 
pillar1: [2]                    pillar2: [5, 4, 3]              pillar3: [6, 1]                 
pillar1: [2, 1]                 pillar2: [5, 4, 3]              pillar3: [6]                    
pillar1: [2, 1]                 pillar2: [5, 4]                 pillar3: [6, 3]                 
pillar1: [2]                    pillar2: [5, 4, 1]              pillar3: [6, 3]                 
pillar1: []                     pillar2: [5, 4, 1]              pillar3: [6, 3, 2]              
pillar1: []                     pillar2: [5, 4]                 pillar3: [6, 3, 2, 1]           
pillar1: [4]                    pillar2: [5]                    pillar3: [6, 3, 2, 1]           
pillar1: [4, 1]                 pillar2: [5]                    pillar3: [6, 3, 2]              
pillar1: [4, 1]                 pillar2: [5, 2]                 pillar3: [6, 3]                 
pillar1: [4]                    pillar2: [5, 2, 1]              pillar3: [6, 3]                 
pillar1: [4, 3]                 pillar2: [5, 2, 1]              pillar3: [6]                    
pillar1: [4, 3]                 pillar2: [5, 2]                 pillar3: [6, 1]                 
pillar1: [4, 3, 2]              pillar2: [5]                    pillar3: [6, 1]                 
pillar1: [4, 3, 2, 1]           pillar2: [5]                    pillar3: [6]                    
pillar1: [4, 3, 2, 1]           pillar2: []                     pillar3: [6, 5]                 
pillar1: [4, 3, 2]              pillar2: [1]                    pillar3: [6, 5]                 
pillar1: [4, 3]                 pillar2: [1]                    pillar3: [6, 5, 2]              
pillar1: [4, 3]                 pillar2: []                     pillar3: [6, 5, 2, 1]           
pillar1: [4]                    pillar2: [3]                    pillar3: [6, 5, 2, 1]           
pillar1: [4, 1]                 pillar2: [3]                    pillar3: [6, 5, 2]              
pillar1: [4, 1]                 pillar2: [3, 2]                 pillar3: [6, 5]                 
pillar1: [4]                    pillar2: [3, 2, 1]              pillar3: [6, 5]                 
pillar1: []                     pillar2: [3, 2, 1]              pillar3: [6, 5, 4]              
pillar1: []                     pillar2: [3, 2]                 pillar3: [6, 5, 4, 1]           
pillar1: [2]                    pillar2: [3]                    pillar3: [6, 5, 4, 1]           
pillar1: [2, 1]                 pillar2: [3]                    pillar3: [6, 5, 4]              
pillar1: [2, 1]                 pillar2: []                     pillar3: [6, 5, 4, 3]           
pillar1: [2]                    pillar2: [1]                    pillar3: [6, 5, 4, 3]           
pillar1: []                     pillar2: [1]                    pillar3: [6, 5, 4, 3, 2]        
pillar1: []                     pillar2: []                     pillar3: [6, 5, 4, 3, 2, 1]     
counter = 63

你可能感兴趣的:(OOP,算法)