这是一个迟到了2个月的博客,还真是不好意思,无论做什么都要持之以恒,更何况学习java呢?更要经常学着、做着、总结着。
我现在要写的是汉诺塔的可视化,就是通过不停画图把汉诺塔的移动过程在画图板上显示出来,当时还不会用别的,想法的也很简单,就是不停的清屏,画圆饼。
当然遇到的第一个问题就是三个托盘用什么表示,想想汉诺塔圆饼在每个托盘都是从小到大,每次只能取顶部那个圆饼,这不是学过的队列吗?那是还没学集合框架,于是自己写了队列类,定义添加,取得和减少长度的方法。
/**
* 存储汉诺塔圆片的队列
* @author 剑晨
*
*/
public class HanoiQueue {
/**添加数据的方法*/
public int[] a=new int[0];
public void add(int data){
int []b=new int[a.length+1];
for(int i=0;i<a.length;i++){
b[i]=a[i];
}
b[a.length]=data;
a=b;
}
/**取出队尾数据的方法*/
public int get(){
int num=a[a.length-1];
return num;
}
/**数组长度减少的方法*/
public void cut(){
int []b=new int[a.length-1];
for(int i=0;i<a.length-1;i++){
b[i]=a[i];
}
a=b;
}
}
第二个问题,就是如何确定圆饼位置和大小,那时还没到对象的程度,没想到把圆饼作为一个个对象,存储着它们位置和大小的信息,只是给每个队列固定的位置,然后是圆饼的大小,首先我要说的是我的队列存的东西,是1234........数字,然后我根据这些数字来确定确定每个圆饼的大小。
/**
* 画出圆盘的方法
*/
public void draw(){
Graphics2D g2=(Graphics2D)g;//使用2D画布
g2.setColor(Color.RED);
for(int i=0;i<A.a.length;i++){//遍历队列A
//圆饼位置和大小有队列数字位置和大小确定
g2.fill3DRect(108- 10 *A.a[i],390-10*i, 20*A.a[i], 10, true);
}
for(int i=0;i<B.a.length;i++){//遍历队列B
g2.fill3DRect(298-10*B.a[i], 390-10*i,20*B.a[i], 10, true);
}
for(int i=0;i<C.a.length;i++){//遍历队列C
g2.fill3DRect(498-10*C.a[i], 390-10*i, 20*C.a[i], 10, true);
}
}
第三个问题就是移动的问题,移动按什么规律呢?开始我想了各种方法始终不行,也想到了递归,可是找不到递归规律。最后求教同学,其实我当时也不太懂,就找了以下,发现这个比较容易懂。
思路如下:
首先考虑极限当只有一个盘的时候 只要 盘直接从 a -> b即可
那么当有2个盘的时候就只要先把1号盘从a -> c 然后 把2号盘 a->b 再 把 2好盘从 c - > b,那么当有n个盘的时候你只要先把 n-1个 盘 借助 b 移动到 c 然后将 n号盘从 a -> b,那么这时候只要将 n-1想办法从c移动到 b 借助 a 那么就可以先把 n-2个盘借助b移动到a,然后 把n-1号盘从c-> b如此递归就是了!
/**
* 每次移动的方法
* @param X、y 队列
*/
public void move(HanoiQueue X,HanoiQueue Y){
g.clearRect(0, 0, 600, 600);
draw(g);//调用画托盘的方法
Y.add(X.get());//队列Y得到队列X队尾数字
X.cut();//队列X队尾数字去除
draw();//调用画圆饼的方法
try{//休眠
Thread.sleep(1000);
}catch(Exception of){}
}
/**
* 递归的方法
* @param count 递归深度
* @param X 、Y、Z 队列
*/
public void hanoi(int count,HanoiQueue X,HanoiQueue Y,HanoiQueue Z){
if(count==1){
move(X,Z);
}else{
//想想刚刚的思路
hanoi(count-1,X,Z,Y);
move(X,Z);
hanoi(count-1,Y,X,Z);
}
}
这样,基本就算解决了所有难题。以下是我做的效果图。