zoukankan      html  css  js  c++  java
  • 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+="
    ";
     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 }

     

  • 相关阅读:
    GC原理---垃圾收集算法
    GC原理---对象可达判断
    散列算法和哈希表结构
    桶排序
    Spring事务梳理
    AQS
    重入锁
    CAS
    研究一下phpspider
    用php写爬虫去爬数据
  • 原文地址:https://www.cnblogs.com/TQCAI/p/7624571.html
Copyright © 2011-2022 走看看