【问题标题】:BFS not returning a pathBFS 不返回路径
【发布时间】:2016-10-01 14:05:51
【问题描述】:

我正在尝试在给定起点和终点的二维数组上实现 BFS。我尝试在网格上给我的函数两个点,但它返回一个空数组,这意味着没有路径。

有人可以指出我哪里出错了,如果可能的话,请帮助我纠正我的错误?谢谢。

public Point[] bfs2(Point start, Point end) {
    boolean[][] visited = new boolean[50][50];
    for (int i = 0; i < visited.length; i++)
        for(int j = 0; j < visited.length; j++)
            visited[i][j] = false;

    visited[start.getX()][start.getY()] = true;
    LinkedList<Point> path = new LinkedList<>();
    Queue<Point> q = new LinkedList<>();
    q.add(start);

    while (!q.isEmpty()) {
        Point next = q.remove(); //i think the error is here
        Point[] neighbours = next.getNeighbours();
        path.add(next);

        if (next.getX() == end.getX() && next.getY() == end.getY())
            break;
        else if (!visited[next.getX()][next.getY()]) {
            for (Point neighbour : neighbours) {
                if (!visited[neighbour.getX()][neighbour.getY()]) {
                    q.add(neighbour);
                }

                visited[neighbour.getX()][neighbour.getY()] = true;
            }
        }
    }

    Point current = path.removeLast();
    ArrayList<Point> v = new ArrayList<>();
    while (current.getX() != start.getX() || current.getY() != start.getY()) {
        v.add(current);
        current = path.removeLast();
    }

    return v.toArray(new Point[v.size()]);
}

编辑:

        Point current=q.peek();
    ArrayList<Point> v=new ArrayList<>();
    if(start.getX()==end.getX() && start.getY()==end.getY()) return new Point[0];
    while(current.getX()!=start.getX() || current.getY()!=start.getY()){
        v.add(current);
        current=current.parent;
    }
    return v.toArray(new Point[v.size()]);

【问题讨论】:

  • 最后 7 行复杂代码而不是简单的 Collections.reverse(path); 的任何原因?
  • 请同时发布您对Point 的定义。更好的是,将其设为 MCVE (stackoverflow.com/help/mcve)
  • (将visited的元素初始化为false是多余的。)
  • 为什么将访问的元素初始化为假冗余?
  • Point是一个存储xy坐标的类,有多种方法,贴出来会很繁琐

标签: java algorithm path-finding breadth-first-search


【解决方案1】:

第一个问题是您将从队列中删除的所有元素添加到路径中(我指的是包含path.add(next); 的行)。

相反,您应该跟踪访问每个节点的父节点。当你找到结束节点时,你可以将你的步骤追溯到开始节点。

如果你已经用尽了所有节点,仍然没有找到结束节点,那么你可以返回一个空列表。

如果您需要MCV example,请告诉我,我会添加它。

后期编辑:

您需要在您的类中添加一个 Point 父字段,如下所示:

class Point {
    int x;
    int y;
    Point parent; // reference to the Point from which this Point was visited

    // constructors, getters, setters, etc.
}

然后您可以更改您的 BFS 实现,以便在迭代其邻居时也为当前节点设置父节点。您必须将循环更改为以下内容:

        for (Point neighbour : neighbours) {
            if (!visited[neighbour.getX()][neighbour.getY()]) {
                q.add(neighbour);
                visited[neighbour.getX()][neighbour.getY()] = true;
                neighbour.parent = next;
            }
        }

【讨论】:

  • 抱歉,如果我的问题含糊不清且不完整,我今天才开始使用堆栈溢出,不习惯正确提问。我的下一个问题是如何跟踪父级,我的代码中的父级在哪里?我试图首先跟踪下一个点,最后得到了一个包含 105 多个项目的数组。
  • 你可以定义一个Points的矩阵来存储父Point,类似于你已经使用的visited矩阵。在将下一个节点标记为已访问时,您还可以在Points 数组中设置其父节点。顺便说一句,Point 是您定义的类还是 java.awt.Point 中定义的类?
  • 我编写了 Point 类。感谢您的回复,但是我仍然不明白如何获得父母。好的,我制作了一个 Point 数组,而不是如何设置每个父级的父级?我真的不明白应该如何设置父母。感谢您的帮助
  • 我现在明白了,我们只是让追溯这些步骤以获得最短路径成为可能。 @Nikopol 你介意检查我的回溯代码逻辑吗,代码是上面更新的帖子(最后)
  • 用于追溯步骤的代码的第一个问题是您的起点。为什么要从队列中的下一个元素初始化 current Point?你应该从你找到的endPoint开始回溯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多