我有一个深度优先的搜索练习.

这项练习的目标是找到一条从迷宫开始到结束的有效路径.

这是我的代码:

Node.java!Node.java!

public class Node
{
    private int position;
    private int type;
    private boolean IsExit;
 
    public Node(int position,int type,boolean IsExit)
    {
        this.position = position;
        this.type = type;
        this.IsExit = IsExit;
    }

    public int getPosition()
    {
        return position;
    }
    
    public int getType()
    {
        return type;
    }
    
    public boolean getIsExit()
    {
        return IsExit;
    }

    public void setIsExit(boolean b)
    {
        IsExit = b;
    }
}

Search算法rithm.java

import java.util.Random;
import java.lang.System;

public class Search算法rithm
{
    protected int gridSize;
    protected int gridLength;
    protected Node[][] grid;
    
    public Search算法rithm(int gridSize)
    {
        int gridLength  = (int) Math.sqrt(gridSize);
        this.gridSize = gridSize;
        this.gridLength = gridLength;
        Node[][]arr = new Node[gridLength][gridLength];
        Random r = new Random();
        for(int i=0;i<gridSize;i++)
        {
            Node n;
            if(i==0)
            {
                n= new Node(i,0,false);
                arr[i][i] = n;
            }
            else if(i==gridSize-1)
            {
                n = new Node(i,0,true);
                arr[gridLength-1][gridLength-1] = n;
            }
            else
            {
                int x = i%gridLength;
                int y = i/gridLength;
                n = new Node(i,r.nextInt(2),false);
                arr[x][y] = n;
            }
        }
        this.grid = arr;
    }
        
    public void print()
    {
        for(int i=0;i<gridLength;i++)
        {
           for(int j=0;j<gridLength;j++)
           {
                System.out.print("Position:"+grid[j][i].getPosition()+" Type:"+grid[j][i].getType()+" ");
           }
           System.out.println();
        }
    }
}

grid是类Node的二维数组:它有2个坐标x和y.x被Node.position%i找到,Y被Node.position/i找到.

DeepFirstSearch.java

import java.lang.System;

public class DeepFirstSearch extends Search算法rithm {
    private  int[] position;

    public DeepFirstSearch(int gridSize) {
        super(gridSize);
        position = new int[2];
        position[0]=0;
        position[1]=0;
    }
    
    public int calc(int[]position)
    {
        System.out.println(grid[position[0]][position[1]].getPosition());
        if(grid[position[0]][position[1]].getType()==1)
        {
           System.out.println("Path been blocked!Exit status:"+1);
           return 1;
        }
        else if(grid[position[0]][position[1]].getIsExit())
        {
            System.out.println("Path been found");
            return 0;
        }
        else
        {
            if(position[0]<gridLength-1)
            {
               position[0]++;
               calc(position);
            }
            if(position[0]>0)
            {
                position[0]--;
                calc(position);
            }
            if(position[1]<gridLength-1)
            {
                position[1]++;
                calc(position);
            }
            if(position[1]>0)
            {
                position[1]--;
                calc(position);
            }
        }
        return -1;
    }
}

int[] position存储当前Node的位置.如果我们用Node.getType()==1命中Node,则路径无效.NodegetIsExit()==true是理想的目的地(在我的示例中它只是1).

#Main.Java#

public class Main {
    public static void main(String[] args) {
        DeepFirstSearch sch = new DeepFirstSearch(9);
        sch.print();
        int[]pos = {0,0};
        sch.calc(pos);
    }
}

我在main函数中将初始位置设置为{0,0}.

问题是,当我运行程序时,我得到这样的输出:

Position:0 Type:0 Position:1 Type:0 Position:2 Type:1 
Position:3 Type:1 Position:4 Type:1 Position:5 Type:1 
Position:6 Type:0 Position:7 Type:1 Position:8 Type:0 
0
1
2
Path been blocked!Exit status:1
1
2
Path been blocked!Exit status:1
1
2
Path been blocked!Exit status:1
1
2
Path been blocked!Exit status:1
1
2
...

因此,它继续下go ,直到抛出StackOverflowException分.为什么该算法一直在访问相同的 node ?

推荐答案

您还没有实现"已访问"的概念.你已经访问过的职位,不应该再访问.这是搜索算法中的一个基本原则.当您准备好查看其邻居 node 时,该 node 称为"已访问".当您对邻居进行递归调用时,该邻居会被访问.如果发现该邻居已被访问,则表明该邻居位于您已遍历的路径上,因此不应再次访问该邻居.如果你愿意,你就会循环 run ,这就是你遇到的问题.

因此,您需要在某个位置维护已访问状态.有很多方法可以做到这一点.一种方法是将一个布尔域添加到Node.

public class Node
{
    private int position;
    private int type;
    private boolean IsExit;
    private boolean isVisited; // See also getter & setter

    public Node(int position,int type,boolean IsExit)
    {
        this.position = position;
        this.type = type;
        this.IsExit = IsExit;
        this.isVisited = false;
    }

    public int getPosition()
    {
        return position;
    }
    
    public int getType()
    {
        return type;
    }
    
    public boolean getIsExit()
    {
        return IsExit;
    }

    public void setIsExit(boolean b)
    {
        IsExit = b;
    }

    public boolean getIsVisited() {
        return isVisited;
    }
    
    public void setIsVisited(boolean b) {
        isVisited = b;
    }
}

我还建议让calc返回boolean,而不是int,因为这就是您在那里所做的事情:要么搜索成功,要么搜索失败.

另一个问题是,在进行递归调用之前对position所做的更改,一旦返回,就应该恢复.否则,下一个相邻位置的计算将是错误的.

因此,举个例子:

    {
        position[0]++;
        calc(position);
    }

应该成为:

    {
        position[0]++;
        calc(position);
        position[0]--; // Bring position back to the original
    }

这是相当麻烦的.此外,position不应该是一个字段;它只是随每个递归调用一起传递的一条本地信息.

如果不将position作为两个数组来传递,而是传递两个单独的int,一个用于row,一个用于col,也会更容易.

以下是更新后的calc方法:

import java.lang.System;

class DeepFirstSearch extends Search算法rithm {
    public DeepFirstSearch(int gridSize) {
        super(gridSize);
    }
        
    public boolean calc(int row, int col)
    {
        // Perform all validity checks here, and test node was not yet visited
        if (   row >= gridLength
            || row < 0
            || col >= gridLength
            || col < 0
            || grid[row][col].getIsVisited()
        ) {
            return false; // Target was not found here
        }
        Node node = grid[row][col];
        node.setIsVisited(true); // Mark as visited
        System.out.println(node.getPosition());
        if (node.getType() == 1)
        {
            System.out.println("Path been blocked!Exit status: false");
            return false; // Target was not found here
        }
        else if(node.getIsExit())
        {
            System.out.println("Path been found");
            return true; // Target found!
        }
        else
        {
            // Use short circuit evaluation: as soon as one of the calls 
            //   returns true, no further calls will be made, and the return
            //   value will be true if and only when that happens.
            return calc(row + 1, col) || calc(row - 1, col) 
                || calc(row, col + 1) || calc(row, col - 1); 
        }
    }
}

初始调用应该是:

class Main {
    public static void main(String[] args) {
        DeepFirstSearch sch = new DeepFirstSearch(9);
        sch.print();
        sch.calc(0, 0);
    }
}

Java相关问答推荐

Spring Webocket:尽管凭据设置为False,但MLhttpsify和Fetch请求之间的CORS行为存在差异

如何在Spring Security中设置CustomLogin路径?

Java 22模式匹配不适用于记录模式匹配.给出汇编问题

同时运行JUnit测试和Selenium/Cucumber测试时出现问题

XPages-在第二次点击按钮之前延迟

如何以干净的方式访问深度嵌套的对象S属性?

如何确定springboot在将json字段转换为Dto时如何处理它?

将java.util.Date转换为OffsetDateTime

如何为JavaFX Spring Boot应用程序制作Windows/MacOS/Linux安装程序

try 将JSON字符串响应从API转换为映射字符串、对象>;时出错

垃圾收集时间长,会丢弃网络连接,但不会在Kubernetes中反弹Pod

当构造函数创建一个新实例时,Java为什么需要&new";

如何用内置Java从JavaFX应用程序中生成.exe文件?

将双倍转换为百分比

如何调整JButton的大小以适应图标?

JavaFX,GridPane:在GridPane的列中生成元素将保持所有列的宽度

为什么Spring要更改Java版本配置以及如何正确设置?

没有Google Play服务,Firebase Auth无法工作

JOOQ:批处理CRUD操作使用动态表定义,如何?

关于正则表达式的一个特定问题,该问题与固定宽度负向后看有关