数据结构隐式图搜索实现

节点类

package Node;

public class Node {

    //用三维数组存储当前状态的情况
   public int [][] currentState = new int[3][3];
    //初始位置没有父状态
    public Node DadState =null;
    //空格变化,可能引起的状态变化有四个,即四个方向,记它变化后的四个状态为四个孩子状态
   public Node child1 = null , child2 = null , child3 = null , child4=null;
    //评估价值的函数 f = g + h ,  h为变化层数,假设初始状态为第0层。下一状态为第1层
    private int f;
    //层数默认初始状态为0层
    public int h=0;

    /**
     * 带参数的构造函数
     * @param States
     * @param dad
     * @param child1
     * @param child2
     * @param child3
     * @param child4
     * @param h
     */
    public Node(int [][]States,Node dad,Node child1,Node child2,Node child3,Node child4,int h){

        //将外界数组传入
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++)
                currentState[i][j]=States[i][j];
        }
        //孩子状态传入
        this.child1 =child1;
        this.child2 =child2;
        this.child3 =child3;
        this.child4 =child4;
        //层数传入
        this.h=h;
    }

    public void setF(int g)
    {
        f=g+h;
    }

    public int getF(){
        return f;
    }
}


操作类

package serves;
import Node.Node;
        import java.util.ArrayList;
        import java.util.List;
        import java.util.Scanner;
public class serves {

    //Node类:数组,父状态,子状态,层数,价值函数f

    Node Begin;
    Node End;

    //open链表记录空格移动后的新状态
    List<Node> open = new ArrayList<>();
    //close链表存储已经确定了的状态
    List<Node> close = new ArrayList<>();

    Scanner scanner=new Scanner(System.in);


    /**
     * 构造函数
     */
    public serves(){

        //题目要求二维数组逐个输入
        System.out.println("起始位置:");
        int [][]startState=new int[3][3];
        int [][]purposeState=new int[3][3];
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++){
                System.out.println("请输入你的数字:");
                startState[i][j]=scanner.nextInt();
            }

        //begin存入初始状态
        Begin = new Node(startState,null,null,null,null,null,0);

        //目标要求二维数组逐个输入
        System.out.println("目标位置:");
        for(int i=0;i<3;i++)
            for (int j = 0; j < 3; j++) {
                System.out.println("请输入你的数字:");
                purposeState[i][j] = scanner.nextInt();
            }

        //End存入结果状态
        End =new Node(purposeState,null,null,null,null,null,0);

    }


    /**
     * 判断题目是否有答案
     * @param begin
     * @param end
     * @return
     */
    public boolean judgeIfResult(Node begin, Node end){

        //用一维数组开始记录展开
        int []oneArray = new int[9];
        int []oneArray2 = new int[9];

        int inverseNumber1  = 0,  inverseNumber2  = 0 , count1 = 0,  count2 = 0;

        //二维数组展开
        int i,j;
        for(i=0;i<3;i++) {
            for(j=0;j<3;j++){
                oneArray[count1++] = begin.currentState[i][j];
                oneArray2[count2++] = end.currentState[i][j];
            }
        }

        //找第一个状态的逆序数
        for(i=0;i<9;i++){
            for(j=0;j<i;j++){
                if(oneArray[j]>oneArray[i] && oneArray[j]!=0 && oneArray[i]!=0)
                    inverseNumber1 ++;
            }
        }

        //找第二个状态的逆序数
        for(i=0;i<9;i++){
            for(j=0;j<i;j++){
                if(oneArray2[j]>oneArray2[i] && oneArray2[j]!=0 && oneArray2[i]!=0)
                    inverseNumber2 ++;
            }
        }
        //判断两个逆序数的奇数偶性是否相等
        if(inverseNumber1 %2 == inverseNumber2 %2)
            return true;
        else
            return false;
    }


    /**
     * 判断是不是已经完成了题目的要求
     * @param begin
     * @param end
     * @return
     */
    public boolean ifFinish (Node begin, Node end) {

        //判断两个二维数组是否一样
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                if(begin.currentState[i][j] != end.currentState[i][j])
                    return false;
            }
        }
        return true;
    }


    /**
     *打印显示移动步骤
     */
    public void printShow(){

        System.out.println("移动步骤如下:");

        for(int count = close.size()-1; count >= 0 ; count--)
        {
            System.out.println("第" + (close.size()-count) + "步:");
            //输出当前已经确定的close链表里的状态的二维数组
            for(int i=0;i<3;i++) {
                for(int j=0;j<3;j++){
                    System.out.print(close.get(count).currentState[i][j]+" ");
                }
                System.out.println();
            }
        }
    }


    /**
     *添加空格移动四个方向之后的四个状态
     * @param parent
     */
    public void addState( Node parent ){

        //存放空格位置
        int count;
        //移动后的新状态
        Node newState;
        //定义四个二维数组用来存储
        int [][]twoArray1 = new int[3][3];
        int [][]twoArray2 = new int[3][3];
        int [][]twoArray3 = new int[3][3];
        int [][]twoArray4 = new int[3][3];

        //把当前状态的二维数组赋值给新定义的四个数组
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                twoArray1[i][j]=parent.currentState[i][j];
                twoArray2[i][j]=parent.currentState[i][j];
                twoArray3[i][j]=parent.currentState[i][j];
                twoArray4[i][j]=parent.currentState[i][j];
            }
        }

        //寻找空格位置
        int x=0,y=0;
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++){
                if(twoArray1[i][j]==0)
                {
                    x=i;
                    y=j;
                }
            }
        }

        //判断空格是否能够上移
        if ( x-1 >= 0)
        {
            //空格赋值
            count = twoArray1[x][y];
            //空格上边的值换到空格位置
            twoArray1[x][y]=twoArray1[x-1][y];
            //空格放到空格上边的位置
            twoArray1[x-1][y]=count;
            //新状态定义
            newState = new Node(twoArray1,null,null,null,null,null,0);

            //判断移动后的状态是否为要求的最终状态
            if (!compare(Begin, newState))
            {
                //设置当前状态为父状态的第一个子状态
                parent.child1 = newState;
                //设置当前状态的父状态
                newState.DadState = parent;
                //层数+1
                newState.h = parent.h + 1;
                //计算g值,即当前状态与最终状态不一样的值的个数
                int count2 = differentNum(newState, End);
                //设置当前状态的f值
                newState.setF(count2);
                //将新状态添加到open链表
                open.add(newState);
            }
        }

        //判断空格是否能够下移
        if ( x+1 <= 2)
        {
            count=twoArray2[x][y];
            twoArray2[x][y]=twoArray2[x+1][y];
            twoArray2[x+1][y]=count;
            newState = new Node(twoArray2,null,null,null,null,null,0);
            if (!compare(Begin, newState))
            {
                parent.child2=newState;newState.DadState=parent;
                newState.h=parent.h+1;
                int count2 =differentNum(newState, End);
                newState.setF(count2);
                open.add(newState);
            }
        }

        //判断空格能不能左移
        if ( y-1 >= 0)
        {
            count=twoArray3[x][y];
            twoArray3[x][y]=twoArray3[x][y-1];
            twoArray3[x][y-1]=count;
            newState = new Node(twoArray3,null,null,null,null,null,0);
            if (!compare(Begin, newState))
            {
                parent.child3=newState;newState.DadState=parent;
                newState.h=parent.h+1;
                int count2=differentNum(newState, End);
                newState.setF(count2);
                open.add(newState);
            }
        }

        //判断空格能不能右移
        if ( y+1 <= 2)
        {
            count=twoArray4[x][y];
            twoArray4[x][y]=twoArray4[x][y+1];
            twoArray4[x][y+1]=count;
            newState = new Node(twoArray4,null,null,null,null,null,0);
            if (!compare(Begin, newState))
            {
                parent.child4=newState;newState.DadState=parent;
                newState.h=parent.h+1;
                int count2=differentNum(newState, End);
                newState.setF(count2);
                open.add(newState);
            }
        }
    }


    /**
     * 比较是否完成运算
     * @param begin
     * @param newState
     * @return
     */
    public boolean compare(Node begin,Node newState){
        //判断是否完成
        if (begin != null && ifFinish(begin,newState))
            return true;

        if (begin.child1 != null)
            compare(begin.child1, newState);
        if (begin.child2 != null)
            compare(begin.child2, newState);
        if (begin.child3 != null)
            compare(begin.child3, newState);
        if (begin.child4 != null)
            compare(begin.child4, newState);
        return false;
    }


    /**
     * 计算g值,即当前状态与最终状态不一样的值的个数
     * @param first
     * @param second
     * @return
     */
    public int differentNum(Node first,Node second){
        int count=0;
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                if(first.currentState[i][j]!=second.currentState[i][j])
                    count++;
        return count;
    }


    /**
     *寻找open链表里面状态F值最小的一个,然后重新排列open,双向冒泡排序
     */
    public void openSort(){

        //替换节点
        Node node;

        int left=0,right= open.size()-1;

        while(left<right)
        {
            for(int i=left+1 ; i <= right ; i++){
                if(open.get( left).getF() > open.get(i).getF() ){
                    node = open.get(i);
                    open.set(i, open.get(left));
                    open.set(left,node);
                }
            }

            left++;

            for(int i=right-1;i >= left ; i--){
                if(open.get(right).getF() < open.get(i).getF()){
                    node= open.get(i);
                    open.set(i, open.get(right));
                    open.set(right,node);
                }
            }

            right--;
        }
    }


    /**
     * 程序执行开关
     */
    public void thisIsStart(){

        //判断题目是否有答案
        if (judgeIfResult(Begin, End)) {

            Node replace = Begin;

            //将初始态加入到Open链表
            open.add(replace);

            //判断是否初始态与结果相同,如果不同
            while(!ifFinish(replace, End)){
                //删除该状态
                open.remove(0);
                //对初始状态运行空格移动的方法
                addState(replace);
                //之后对open链表进行排序
                openSort();
                //将open链表里f值最小的一个赋值给replace
                replace = open.get(0);
            }

            //将replace添加到close链表中
            Node willAddClose = replace;
            while (willAddClose != null)
            {
                close.add(willAddClose);
                willAddClose = willAddClose.DadState;
            }
            //打印输出
            printShow();
        }

        //没有答案
        else{
            System.out.println("没有结果!");
        }
    }

}


测试

package test;
import serves.serves;

public class test {
    public static void main(String[]args){
        serves serves = new serves();
        serves.thisIsStart();
    }
}


运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值