法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
这就是所谓的汉诺塔问题,也称河内塔。如果柱子标为ABC,要由A搬至C,在只有一个盘子时,就将它直接搬至C,当有两个盘子,就将B当作辅助柱。如果盘数超过2个,将第三个以下的盘子遮起来,就很简单了,每次处理两个盘子,也就是:A->B、A ->C、B->C这三个步骤,而被遮住的部份,其实就是进入程式的递回处理。事实上,若有n个盘子,则移动完毕所需之次数为2^n - 1,所以当盘数为64时,则所需次数为:264- 1 = 18446744073709551615为5.05390248594782e+16年,也就是约5000世纪,如果对这数字没什幺概念,就假设每秒钟搬一个盘子好了,也要约5850亿年左右。
简单逻辑代码
public static void main(String[] args) {
hanoi(64,'A','B','C');
}
public static void hanoi(int n, char A, char B, char C) {
if(n == 1) {
System.out.println("移动" + n +"个盘子从"+ A + "到" + C);
}else {
hanoi(n-1,A,C,B);
System.out.println("移动" + n +"个盘子从"+ A + "到" + C);
hanoi(n-1,B,A,C);
}
}
通过递归的方式实现对盘子的移动。简单说
1个盘子 直接从A移动到C
2个盘子 将1号盘子从A移动到B,再将2号盘子从A移动到C,再将1号盘子从B移动到C
3个盘子 将1,2号从A移动到B,再将3号从A移动到C,再将1,2号从B移动到C
....
这就是递归的思想,考虑移动64个盘子,其实就是将前63个从A移动到B,将64号从A移动到C,接着思考63个盘子从B移动到C的问题,也就是将62个盘子从B移动到A,再将63号盘子从B移动到C....依次类推,完整代码如下:
public static int COUNT =0;//标记移动次数
public static int NUMBER = 3;//圆盘的数量
//实现移动的函数
public static void move(int disks,String N,String M)
{
System.out.println("第" + ( ++COUNT ) +" 次移动 : " +" 把 "+disks+" 号圆盘从 " + N +" ->移到->" + M);
}
//递归实现汉诺塔的函数
public static void hanoi(int n,String A,String B,String C)
{
if(n == 1)//圆盘数只有一个时,只需将其从A<金柱>塔移到C<铜柱>塔
TowersOfHanoi.move(1, A, C);//将编号为1的圆盘从A<金柱>移到C<铜柱>
else
{//否则
hanoi(n - 1, A, C, B);//递归,把A<金柱>塔上编号1~n-1的圆盘移到B<银柱>上,以C<铜柱>为辅助塔
TowersOfHanoi.move(n, A, C);//把A<金柱>塔上编号为n的圆盘移到C<铜柱>上
hanoi(n - 1, B, A, C);//递归,把B<银柱>塔上编号1~n-1的圆盘移到C<铜柱>上,以A<金柱>为辅助塔
}
}
public static void main(String[] args) {
System.out.println("***************************************");
System.out.println(" 经典算法之汉诺塔求解 ");
System.out.println("***************************************");
TowersOfHanoi.hanoi(NUMBER, "金柱","银柱", "铜柱");
System.out.println(">>移动了" + COUNT + "次,把金柱上的圆盘都移动到了铜柱上");
}