Hanio塔问题
问题说明:将柱子A上的盘子,借助柱子B,移动到C柱子上,并保持与原来A柱子上的位置顺序一致。最顶部为1号。
解决该问题的方案,最经典的是递归思想。
一、Hanoi(汉诺塔)递归算法
Hanoi递归算法 源码:
/**
* Hanoi(汉诺塔)递归算法
*/
package hanoi;
import java.util.Scanner;
public class Hanoi {
public static int times; //times记录移动的次数
public static void main(String[] args) {
//定义A、B、C三根柱子
char A = 'A';
char B = 'B';
char C = 'C';
System.out.println("汉诺塔游戏");
System.out.println("请输入盘子数:");
Scanner s = new Scanner(System.in);
int n = s.nextInt();
//调用汉诺塔
hannoi(n, A, B, C);
s.close();
}
/**
* 汉诺塔演示
*/
public static void hannoi(int n, char A, char B, char C){
if(n == 1){
move(n, A, C);
}else{
//移动上一关的步骤移动到B
hannoi(n-1, A, C, B);
//把最大的盘子移动C塔
move(n, A, C);
//再把B上的上一关的盘子移动到C上就可以了
hannoi(n-1, B, A, C);
}
}
/**
* 移动盘子,将disk号盘子从M移到N
*/
public static void move(int disk, char M, char N ){
System.out.println("第"+(++times)+"次移动, 盘子"+disk+ " "+M+"------->"+N);
}
}
3、运行结果
4、算法分析
以 n=3 为例,实际移动步骤为:
可以看出三个明显的递归模块,递归实现的移动步骤为 1~7 的顺序。
函数调用三件事:
- 系统将所有实参指针、返回地址等信息传递给被调用函数;
- 在调用函数的方法栈中为被调用函数的局部变量分配储存区;
- 将控制转移到被调用函数入口。
函数返回三件事:
- 系统保存被调用函数的计算结果;
- 释放分配给被调用函数的数据区;
- 依照被调用函数保存的返回地址将控制转移到调用函数。
递归算法优缺点:
- 优点:结构简单、可读性强、设计调试方便。
- 缺点:频繁大量地调用自身函数和返回,CPU对执行程序的转移会耗费较长时间,并占用较多存储空间用于保存现场和转移信息。
时间复杂度:
Hanoi塔算法中,n个盘子的移动次数为2n-1,因此时间复杂度为 O( 2n ) 。