一.传说:
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
二.数学问题:
有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数
解:(1)n == 1
第1次 1号盘 A---->C
sum = 1 次
(2) n == 2
第1次 1号盘 A---->B
第2次 2号盘 A---->C
第3次 1号盘 B---->C
sum = 3 次
(3)n == 3
第1次 1号盘 A---->C
第2次 2号盘 A---->B
第3次 1号盘 C---->B
第4次 3号盘 A---->C
第5次 1号盘 B---->A
第6次 2号盘 B---->C
第7次 1号盘 A---->C
sum = 7 次
不难发现规律:
1个圆盘的次数 2的1次方减1
2个圆盘的次数 2的2次方减1
3个圆盘的次数 2的3次方减1
。 。 。 。 。
n个圆盘的次数 2的n次方减1
故:移动次数为:2^n - 1
三.递归算法:
我们在利用计算机求汉诺塔问题时,必不可少的一步是对整个实现求解进行算法分析。到目前为止,求解汉诺塔问题最简单的算法还是同过递归来求。
实现这个算法可以简单分为三个步骤:
(1) 把n-1个盘子由A 移到 B;
(2) 把第n个盘子由 A移到 C;
(3) 把n-1个盘子由B 移到 C;
从这里入手,在加上上面数学问题解法的分析,我们不难发现,移到的步数必定为奇数步:
(1)中间的一步是把最大的一个盘子由A移到C上去;
(2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到了B上,
(3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上;
public class Hanoilmpl { public static void hanoi(int n, char A, char B, char C) { if (n == 1) { move(A, C); } else { hanoi(n - 1, A, C, B);//将n-1个盘子由A经过C移动到B move(A, C); //执行最大盘子n移动 hanoi(n - 1, B, A, C);//剩下的n-1盘子,由B经过A移动到C } } private static void move(char A, char C) {//执行最大盘子n的从A-C的移动 System.out.println("move:" + A + "--->" + C); } public static void main(String[] args) { System.out.println("移动汉诺塔的步骤:"); hanoi(3, 'a', 'b', 'c'); } }
最后贴一个在博客上看到的故事,挺有趣的:
对递归的理解的要点主要在于放弃!
放弃你对于理解和跟踪递归全程的企图,只理解递归两层之间的交接,以及递归终结的条件。
想象你来到某个热带丛林,意外发现了十层之高的汉诺塔。正当你苦苦思索如何搬动它时,林中出来一个土著,毛遂自荐要帮你搬塔。他名叫二傻,戴着一个草帽,草帽上有一个2字,号称会把一到二号盘搬到任意柱。
你灵机一动,问道:“你该不会有个兄弟叫三傻吧?” “对对,老爷你咋知道的?他会搬一到三号盘。“ ”那你去把他叫来,我不需要你了。“
于是三傻来了,他也带着个草帽,上面有个3字。
你说:”三傻,你帮我把头三个盘子移到c柱吧。“ 三傻沉吟了一会,走进树林,你听见他大叫:”二傻,出来帮我把头两个盘子搬到C!“
由于天气炎热你开始打瞌睡。朦胧中你没看见二傻是怎么工作的,二傻干完以后,走入林中大叫一声:“老三,我干完了!”
三傻出来,把三号盘从A搬到B,然后又去叫二傻:“老二,帮我把头两个盘子搬回A!”
余下的我就不多说了,总之三傻其实只搬三号盘,其他叫二傻出来干。最后一步是三傻把三号盘搬到C,然后呼叫二傻来把头两个盘子搬回C
事情完了之后你把三傻叫来,对他说:“其实你不知道怎么具体一步一步把三个盘子搬到C,是吧?”
三傻不解地说:“我不是把任务干完了?”
你说:“可你其实叫你兄弟二傻干了大部分工作呀?”
三傻说:“我外包给他和你屁相干?”
你问到:“二傻是不是也外包给了谁?“
三傻笑了:“这跟我有屁相干?”
你苦苦思索了一夜,第二天,你走入林中大叫:“十傻,你在哪?”
一个头上带着10号草帽的人,十傻,应声而出:“老爷,你有什么事?”
“我要你帮把1到10号盘子搬到C柱“
“好的,老爷。“十傻转身就向林内走。
“慢着,你该不是回去叫你兄弟九傻吧“
“老爷你怎么知道的?“
“所以你使唤他把头九个盘子搬过来搬过去,你只要搬几次十号盘就好了,对吗?“
“对呀!“
“你知不知道他是怎么干的?“
“这和我有屁相干?“
你叹了一口气,决定放弃。十傻开始干活。树林里充满了此起彼伏的叫声:“九傻,来一下!“
“老八,到你了!““五傻!。。。“”三傻!。。。“”大傻!“
你注意到大傻从不叫人,但是大傻的工作也最简单,他只是把一号盘搬来搬去。
若干年后,工作结束了。十傻来到你面前。你问十傻:“是谁教给你们这么干活的?“
十傻说:“我爸爸。他给我留了这张纸条。”
他从口袋里掏出一张小纸条,上面写着:“照你帽子的号码搬盘子到目标柱。如果有盘子压住你,叫你上面一位哥哥把他搬走。如果有盘子占住你要去的柱子,叫你哥哥把它搬到不碍事的地方。等你的盘子搬到了目标,叫你哥哥把该压在你上面的盘子搬回到你上头。“
你不解地问:“那大傻没有哥哥怎么办?“
十傻笑了:“他只管一号盘,所以永远不会碰到那两个‘如果’,也没有盘子该压在一号上啊。”
但这时他忽然变了颜色,好像泄漏了巨大的机密。他惊慌地看了你一眼,飞快地逃入树林。
第二天,你到树林里去搜寻这十兄弟。他们已经不知去向。你找到了一个小屋,只容一个人居住,但是屋里有十顶草帽,写着一到十号的号码