相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
前提:默认是最底下、最大的圆盘是第n个圆盘,设n远大于1。
(注:下面所说的都是想法,而不是具体实现,不要在看到这些文字时就代入代码里面,而是先理解这些文字的意思!)
要想完成整个移动,我们可以这样子想:
可能有人就会有疑问了,“每次只能移动一个盘子,这里一下移动了n-1个盘子,明显不符合要求啊“,暂且保留这个问题,顺着思路继续向下走。
定义方法move
,用来实现递归算法,其中参数n表示圆盘的个数,a表示源柱,b表示辅助柱,c表示目录柱,算法最终实现“打印将源柱a上的圆盘移动到目标柱c上的所有步骤”。
/*
* @param n 圆盘数量
* @param a 源柱
* @param b 辅助柱
* @param c 目标柱
*/
public static void move(int n, char a, char b, char c) {
}
当源柱上只有一个圆盘时,可以直接将源柱上的这个圆柱移动到目标柱上,这就是递归终止条件。
/*
* @param n 圆盘数量
* @param a 源柱,只是记录一个符号,没有实际含义
* @param b 辅助柱,只是记录一个符号,没有实际含义
* @param c 目标柱,只是记录一个符号,没有实际含义
*/
public static void move(int n, char a, char b, char c) {
if (n == 1) {
// 如果源柱上只有一个圆盘,直接将圆盘从源柱a上移动到目标柱c上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
}
}
在递归的非终止条件中,将完成算法逻辑中所示的三个步骤
public static void move(int n, char a, char b, char c) {
if (n == 1) {
// 如果源柱上只有一个圆盘,直接将圆盘从源柱a上移动到目标柱c上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
} else {
// 步骤1: 将 n - 1(从上至下)个圆盘,移动到辅助柱上
move(n - 1, a, c, b);
// 步骤2: 将第 n 个圆盘移动到目标柱上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
// 步骤3: 将 n - 1 个圆盘从辅助柱上移动到目标柱上,此时a作为辅助柱
move(n - 1, b, a, c);
}
}
// 步骤1: 将 n - 1(从上至下)个圆盘,移动到辅助柱上
move(n - 1, a, c, b);
// 步骤2: 将第 n 个圆盘移动到目标柱上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
// 步骤3: 将 n - 1 个圆盘从辅助柱上移动到目标柱上,此时a作为辅助柱
move(n - 1, b, a, c);
至此,一次函数回归分析完毕,后续执行类似。
public class Hanoi {
public static void main(String[] args) {
move(3, 'a', 'b', 'c');
}
/*
* @param n 圆盘数量
* @param a 源柱
* @param b 辅助柱
* @param c 目标柱
*/
public static void move(int n, char a, char b, char c) {
if (n == 1) {
// 如果源柱上只有一个圆盘,直接从源柱a上移动到目标柱c上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
} else {
// 步骤1: 将 n - 1(从上至下)个圆盘,移动到辅助柱上
move(n - 1, a, c, b);
// 步骤2: 将第 n 个圆盘移动到目标柱上
System.out.printf("从%s上移动第%d个圆盘到%s上\n", a, n, c);
// 步骤3: 将 n - 1 个圆盘从辅助柱上移动到目标柱上,此时a作为辅助柱
move(n - 1, b, a, c);
}
}
}