死磕算法第二弹附加篇——汉诺塔
汉诺塔
栈的数据结构非常适合汉诺塔来解释,因为二者的操作原理是一样的,由此也衍生了针对汉诺塔的依稀额算法。其中一个就是三根柱子的汉诺塔的移动步骤。
汉诺塔的移动原理
这里我们详细的介绍一个汉诺塔的移动原理,假设三根柱子分别是A、B、C,一开始A上有N个圆盘,从小到大、从上到下分别是1、2......N-1、N,我们要把A上的N个圆盘远不移动到C上面,而每次只能移动每根柱子上面的一个圆盘。
我们可以反过来考虑一下,若要把A上的圆盘全部移动到C上,那么需要把前N-1的盘子按照顺序落到B上了,最后的第N个圆盘才能够直接从A移动到C上,从而完成第N个圆盘的移动。之后把B的N-2个圆盘移动到A上,再把B上剩下的一个圆盘,也就是N-1个圆盘直接移动到C上,这是就已经完成最下面的两个圆盘的移动,继续这样的移动,直接就完成有洗。
汉诺塔的递归实现
上面的步骤在代码上使用递归是最好实现的,要使用递归,就要考虑到需要进行递归的部分是那部分。
public class Hanoi {
private static int moveNum = 0;
private static void hanoi(int n, char a, char b, char c) {
if (n == 1) {
//如果只有一个圆盘,只需要移动就好
move(a, c);
return;
}
//先把A上的n-1个元哦按移动到B上
hanoi(n - 1, a, c, b);
//把A上的最后一个圆盘移动到C上
move(a, c);
//接下来递归,把B上的n-1个圆柱移动到C上
hanoi(n - 1, b, a, c);
}
private static void move(char a, char c) {
moveNum++;
System.out.println(a + "--->" + c);
}
public static void main(String[] args) {
hanoi(3,'A','B','C');
System.out.println(moveNum);
}
}
hanoi函数的第1个参数就是柱子上需要移动的元哦按的个数,后三个参数分别为一根柱子的标识。首先当n为1时,需要移动的圆盘只有一个,直接把A上的圆盘移动到C上就可以了,同时代码结束,因为已经没有需要移动的圆盘了。
接下来就是实现汉诺塔实现的关键,即把A上的所有圆盘移动到C上,需要先把A最上面的n-1个圆盘移动到B上,于是有了“hanoi(n-1,a,c,b)”,就可以完成移动,这就是递归调用的思想所在了。
在递归调用中会继续执行该方法,改变参数的值,继续打印,这样每次调用会减少n的值,直到n最后变为1之后,结束递归调用,最终完成汉诺塔移动。
转变一下思想,就能够理解从B上移动n-1个圆盘到C上其实和从A上移动元哦按到C上是一样的。
不要让以后的自已,为曾经的不够努力而伤悲