K:汉诺塔问题

相关介绍:

 汉诺塔问题是一个通过隐式使用递归栈来进行实现的一个经典问题,该问题最早的发明人是法国数学家爱德华·卢卡斯。传说印度某间寺院有三根柱子,上串64个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。但不知道是卢卡斯自创的这个传说,还是他受他人启发。若传说属实,僧侣们需要2^64 − 1步才能完成这个任务;若他们每秒可完成一个盘子的移动,就需要5845亿年才能完成。整个宇宙现在也不过137亿年。这个传说有若干变体:寺院换成修道院、僧侣换成修士等等。寺院的地点众说纷纭,其中一说是位于越南的河内,所以被命名为“河内塔”。另外亦有“金盘是创世时所造”、“僧侣们每天移动一盘”之类的背景设定。佛教中确实有“浮屠”(塔)这种建筑;有些浮屠亦遵守上述规则而建。“汉诺塔”一名可能是由中南半岛在殖民时期传入欧洲的。

 其问题的形式化描述如下:假设有3个分别命名为X,Y,Z的塔座,在塔座X上插有n个直径大小各不相同,且从小到大编号为1、2、......、n的圆盘。现要求将塔座X上的n个圆盘借助塔座Y移至塔座Z上,并仍按同样顺序叠排。圆盘移动时必须遵守以下的规则:

  1. 每次只能移动一个圆盘
  2. 圆盘可以插在X、Y和Z中的任意一个塔座上
  3. 任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。

问题分析:

 当n=1时,问题较为简单,只要将编号为1的圆盘从塔座X直接移动到塔座Z上即可;当n>1时,需利用塔座Y作辅助塔座,若能先设法将压在编号为n的圆盘上的n-1个圆盘从塔座X移动到塔座Y上,则可将编号为n的圆盘从塔座X移动至塔座Z上,然后将塔座Y上的n-1个圆盘移至塔座Z上。而如何将n-1个圆盘从一个塔座移动至另一个塔座是一个和原问题具有相同特征属性的问题,只是问题的规模小于1,因此可以用同样的办法进行求解。由此可知,求解n阶汉诺塔问题可以用递归分解的方法来进行。

示例代码如下:

package queueandstack;
/**
 * 该类用于解决汉诺塔问题
 * @author 学徒
 *
 */
public class Hanoi
{
	//用于搬动次数的记录
	private int c=0;
	/**
	 * 将塔座x上按照直径由小到大且自上而下的编号为1至n的n个圆盘按照规则移到塔座z上,y用作辅助塔座
	 * @param n 圆盘的数目
	 * @param x 原塔座
	 * @param y 辅助塔座
	 * @param z 目标塔座
	 */
	public void hanoi(int n,char x,char y,char z)
	{
		if(n==1)
			move(x,1,z);//将编号为1的圆盘从x移动到z
		else
		{
			hanoi(n-1,x,z,y);//将x上编号为1到n-1的圆盘移动到y,z做辅助塔座
			move(x,n,z);//将编号为n的圆盘从x移动到z
			hanoi(n-1,y,x,z);//将y上编号为1至n-1的圆盘移动到z,x做辅助塔座
		}
	}
	/**
	 * 用于移动操作
	 * @param x 原塔座
	 * @param n 圆盘编号
	 * @param z 目标塔座
	 */
	public void move(char x,int n,char z)
	{
		System.out.println("第"+(++c)+"次移动:"+n+"号圆盘,"+x+"->"+z);
	}
	
	public static void main(String[] args)
	{
		Hanoi n=new Hanoi();
		n.hanoi(3, 'x', 'y', 'z');//对圆盘数量为3进行移动
	}
}



运行结果:
第1次移动:1号圆盘,x->z
第2次移动:2号圆盘,x->y
第3次移动:1号圆盘,z->y
第4次移动:3号圆盘,x->z
第5次移动:1号圆盘,y->x
第6次移动:2号圆盘,y->z
第7次移动:1号圆盘,x->z

-------------->以上内容大部分来自教材《数据结构》,清华大学出版社

其移动情况的示例图如下:

三阶汉诺塔移动情况图

回到目录|·(工)·)

posted @ 2018-01-07 11:38  林学徒  阅读(...)  评论(...编辑  收藏