“这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战”
一、汉诺塔
需求:打印n层汉诺塔从最左边移动到最右边的全部过程。
要求只能小压大,不能大压小,即小的盘子能放在大的盘子上,大的盘子不能放在小的盘子上。
二、思路
先从最经典的3层汉诺塔一步一步求解。
总共3个盘子:想办法先把前2个盘子移动到中间,然后把最后一个盘子移动到最右边,然后再把中间的盘子移动到最右边。至于怎么移动,只需满足小压大规则即可,总共三步。
- 第一步:{1,2}盘子从左边移动到中间(左->中)
- 第一步:{1}盘子从左移动到右边(左->右)
- 第二步:{2}盘子从左边移动到中间(左->中)
- 第三步:{1}盘子从右边移动到中间(右->中)
- 第二步:{3}盘子从左边移动到右边 (左->右)
- 第三步:{1,2}盘子从中间移动到右边 (中->右)
- 第一步:{1}从中间移动到左边(中->左)
- 第二步:{2}从中间移动到右边(中->右)
- 第三步:{1}从左边移动到右边(左->右)
三、解答
1. 方式一
如果有N个盘子,可以推出,先把1 ~ N-1个盘子从左边移动到中间,然后第N个盘子从左边移动到右边,最后把1 ~ N-1盘子从中间移动到右边的,分成3步,每步又可以拆分为一小部分进行求解。
public static void hanoi1(int n) {
leftToRight(n);
}
private static void leftToRight(int n) {
if (n == 1) {
System.out.println("Move 1 from left to right");
return;
}
leftToMid(n - 1);
System.out.println("Move " + n + " from left to right");
midToRight(n - 1);
}
private static void leftToMid(int n) {
if (n == 1) {
System.out.println("Move 1 from left to mid");
return;
}
leftToRight(n - 1);
System.out.println("Move " + n + " from left to mid");
rightToMid(n - 1);
}
private static void midToRight(int n) {
if (n == 1) {
System.out.println("Move 1 from mid to right");
return;
}
midToLeft(n - 1);
System.out.println("Move " + n + " from mid to right");
leftToRight(n - 1);
}
private static void rightToMid(int n) {
if (n == 1) {
System.out.println("Move 1 from right to mid");
return;
}
rightToLeft(n - 1);
System.out.println("Move " + n + " from right to mid");
leftToMid(n - 1);
}
private static void midToLeft(int n) {
if (n == 1) {
System.out.println("Move 1 from mid to left");
return;
}
midToRight(n - 1);
System.out.println("Move " + n + " from mid to left");
rightToLeft(n - 1);
}
private static void rightToLeft(int n) {
if (n == 1) {
System.out.println("Move 1 from right to left");
return;
}
rightToMid(n - 1);
System.out.println("Move " + n + " from right to left");
midToLeft(n - 1);
}
public static void main(String[] args) {
hanoi1(3);
}
2. 方式二
方式一可不可以进行进一步的抽象化,通过参数控制向左移动(右->左,右->中)还是向右移动(左->右,中->右)。
public static void hanoi2(int n) {
if (n > 0) {
process(n, "left", "right", "mid");
}
}
private static void process(int n, String from, String to, String other) {
if (n == 1) {
System.out.println("Move 1 from " + from + " to " + to);
} else {
process(n - 1, from, other, to);
System.out.println("Move " + n + " from " + from + " to " + to);
process(n - 1, other, to, from);
}
}
public static void main(String[] args) {
hanoi2(3);
}
四、总结
汉诺塔问题还可以采用非递归解决,有兴趣的同学自行了解哈!