BFS实现8数码问题,思考与总结
BFS实现8数码问题,思考与总结
今天中午学习了二叉树的线索化与线索化遍历,突然有一种想实现八数码问题的冲动,因为它的初级解决方式是BFS(广度优先搜索算法)。于是我开始编程。
没想到一编就是一个下午,一直编到了晚上8点。期间出现了很多问题。
1.拷贝函数拷贝完之后,对目标对象进行的操作,会影响源对象。
原来的代码:
1 ints(ints obj){//拷贝构造函数 2 int i,j; 3 data=new myInt[3][3]; 4 for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data 5 data[i][j]=obj.data[i][j];//问题点 6 } 7 this.parent=obj.parent;}//拷贝父编号
修改后:
1 ints(ints obj){//拷贝构造函数 2 int i,j; 3 data=new myInt[3][3]; 4 for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data 5 data[i][j]=new myInt(); 6 data[i][j].set(obj.data[i][j].get()); 7 } 8 this.parent=obj.parent;//拷贝父编号 9 }
这个问题涉及到了java的对象引用方式。在出现问题的语句上,我直接使用了“=”进行赋值,传给等号左边的相当于只是右边的指针,而不是值,因为没有用“new”新建对象。修改后,新建了对象,并且进行了传值。
2.程序能跑起来,但是一直处于循环状态,无法跑出正确的答案。
开始我按照脑海里的“BFS是树的按层遍历”来编制代码。写完后发现出现了问题。
原先的代码:
1 while(front<rear){ 2 int lastRear=rear; //临时队尾 3 for(int i=front;i<lastRear;i++){ //树的按层遍历。对当前层全部执行出队操作。 4 ints tmp=queue.get(front++); //出队 5 //对这个出队节点进行四个方向上的变换,构造出新的叶子节点,让他们入队 6 for(int j=0;j<4;j++){ //进行4个方向上的变换 7 ints node=new ints(tmp); //拷贝出新的结点 8 if(node.Move(j) && (!FindInQueue(node)) ){ //如果变换成功 并且这个结点在队列中是新的 9 node.parent=front-1; 10 if(node.FindTarget(target)){ 11 System.out.println("找到"); 12 System.out.println(node); 13 return; //找到目标,跳出循环 14 } 15 queue.add(node); 16 rear++; //入队 17 System.out.println(node); 18 } 19 } 20 } 21 }
按层遍历是试用一个队列,首先根节点入队,然后由根节点派生出叶子节点入队,遍历每一层,使树一层一层增加,进行遍历。
java源码
1 import java.util.*; 2 3 public class demo { 4 5 public demo() { 6 // TODO Auto-generated constructor stub 7 } 8 9 public static void main(String[] args) { 10 EightNumProblem proble=new EightNumProblem(); 11 proble.solve(); 12 } 13 14 } 15 16 class EightNumProblem{ 17 int source[][] ={{1,2,3},{4,5,0},{6,7,8}};//构造一个二维 3 * 3 数组【源数据】 18 int target[][] ={{1,2,3},{4,5,6},{7,8,0}};//构造一个二维 3 * 3 数组【目标数据】 19 class myInt{ 20 int i=0; 21 int get(){return i;} 22 void set(int in){i=in;} 23 myInt(){} 24 myInt(int in){i=in;} 25 } 26 class ints{ //解决问题的数据结构。 27 protected myInt[][] data=new myInt[3][3];//内部数据 28 protected int parent;//父编号,用于回溯 29 ints(){ 30 31 } 32 ints(ints obj){//拷贝构造函数 33 int i,j; 34 data=new myInt[3][3]; 35 for(i=0;i<3;i++) for(j=0;j<3;j++){//拷贝data 36 data[i][j]=new myInt(); 37 data[i][j].set(obj.data[i][j].get()); 38 } 39 this.parent=obj.parent;//拷贝父编号 40 } 41 ints(int[][] in){ 42 int i,j; 43 for(i=0;i<3;i++) for(j=0;j<3;j++) data[i][j]=new myInt(in[i][j]); 44 } 45 int get(int i,int j){ 46 return data[i][j].get(); 47 } 48 void set(int i,int j,int in){ 49 data[i][j].set(in); 50 } 51 public String toString(){//重写用于打印 52 int i,j; 53 String re=new String(""); 54 for(i=0;i<3;i++){ 55 for(j=0;j<3;j++){ 56 re+=Integer.toString(data[i][j].get()); 57 if(j!=2) re+=",";} 58 re+="\n"; 59 } 60 return re; 61 } 62 void FindPos(int target,myInt X,myInt Y){//寻找目标元素,并传指 X、Y 返回。 63 int i,j; 64 for(i=0;i<3;i++) for(j=0;j<3;j++) if(target==data[i][j].get()){//循环,找到目标元素 65 X.set(i);//传指 66 Y.set(j); 67 return; 68 } 69 } 70 boolean Move(int mod){ 71 myInt X=new myInt(); 72 myInt Y=new myInt(); 73 FindPos(0,X,Y); 74 int x=X.get(); 75 int y=Y.get();//找到0的位置 76 // System.out.println("x="+x+"y="+y); 77 switch(mod){ 78 case 0://上 79 if(y>0) swap(x,y,x,y-1); 80 else return false; 81 break; 82 case 1://下 83 if(y<2) swap(x,y,x,y+1); 84 else return false; 85 break; 86 case 2://左 87 if(x>0) swap(x,y,x-1,y); 88 else return false; 89 break; 90 default://右 91 if(x<2) swap(x,y,x+1,y); 92 else return false; 93 break; 94 } 95 return true; 96 } 97 void swap(int x1,int y1,int x2,int y2){//(x1,y1)与(x2,y2)交换 98 int tmp=data[x1][y1].get(); //tmp=x1 99 data[x1][y1].set(data[x2][y2].get()); //x1=x2 100 data[x2][y2].set(tmp); //x2=tmp 101 } 102 boolean FindTarget(int[][] obj){//找到目标 103 int i,j; 104 for(i=0;i<3;i++) for(j=0;j<3;j++) if(obj[i][j]!=data[i][j].get()) return false;//只要有一个不符,错误 105 return true; 106 } 107 boolean equalWith(ints obj){//与目标相同 108 int i,j; 109 for(i=0;i<3;i++) 110 for(j=0;j<3;j++) 111 if(obj.data[i][j].get()!=data[i][j].get()) return false;//只要有一个不符,错误 112 return true; 113 } 114 } 115 116 List<ints> queue=new ArrayList<ints>();//设置队列 117 118 EightNumProblem(){} 119 120 boolean FindInQueue(ints elem){//查看队列中是否有该元素 121 for(int i=0;i<queue.size();i++){ 122 if(elem.equalWith(queue.get(i))){ 123 return true; 124 } 125 } 126 127 return false; 128 } 129 130 void solve(){ 131 ints root=new ints(source);//用源数据构造根节点 132 root.parent=-1;//父编号设置特殊值: -1 133 int front=0; 134 int rear=0; 135 queue.add(root);//根节点入队 136 rear++; 137 int flag=0; 138 while(front<rear && flag<100000){ 139 for(int j=0;j<4;j++){ 140 flag++; 141 ints tmp=queue.get(front); //出队 142 ints node=new ints(tmp); //拷贝出新的结点 143 if(node.Move(j) && (!FindInQueue(node)) ){ //如果变换成功 并且这个结点在队列中是新的 144 node.parent=front; 145 if(node.FindTarget(target)){ 146 System.out.println("找到"); 147 PrintSource(node); 148 return; //找到目标,跳出循环 149 } 150 queue.add(node); 151 rear++; //入队 152 } 153 } 154 front++; 155 } 156 } 157 void PrintSource(ints obj){ 158 while(obj.parent!=-1){ 159 System.out.println(obj); 160 obj=queue.get(obj.parent); 161 } 162 } 163 }