BFS实现8数码问题,思考与总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 


 

以上是关于BFS实现8数码问题,思考与总结的主要内容,如果未能解决你的问题,请参考以下文章

BFS-八数码问题与状态图搜索

Acwing 179 八数码问题 (bfs or A*)

洛谷 P1379 八数码难题 Label:判重&&bfs

[A*] aw179. 八数码(A*+bfs最小步数模型+模板题)

洛谷P1379 八数码难题(bfs)

BFS八数码问题