简体   繁体   中英

Shortest path from Start to end point using BFS

I want to display the shortest path if exists from the given starting point represented as S to endpoint E . I have a matrix with value 0 indicating no path and 1 indicating a valid path to visit. I can visit row-wise and column-wise but not diagonal way. Now using BFS I can get the shortest path value as an integer using the below code:

public static void main(String[] args) {

    int r = findShortestPathBFS(new char[][] { "0001110011".toCharArray(), "1111011110".toCharArray(),
            "0110001010".toCharArray(), "S010101011".toCharArray(), "1110111E01".toCharArray() }, 3, 0);
    System.out.println(r);
}

private static int findShortestPathBFS(char arr[][], int startX, int startY) {
    if (arr[startX][startY] == 'E')
        return 0;
    int moveX[] = new int[] { 0, 0, 1, -1 };
    int moveY[] = new int[] { 1, -1, 0, 0 };
    boolean visited[][] = new boolean[arr.length][arr[0].length];
    Queue<QNode> qNodes = new LinkedList<>();
    qNodes.add(new QNode(startX, startY, 0));
    while (!qNodes.isEmpty()) {
        QNode currNode = qNodes.remove();
        int currX = currNode.x;
        int currY = currNode.y;
        int currDistance = currNode.distance;
        visited[currX][currY] = true;
        // System.out.println(arr[currX][currY]);
        if (arr[currX][currY] == 'E')
            return currDistance;

        for (int i = 0; i < moveX.length; i++) {
            int newX = currX + moveX[i];
            int newY = currY + moveY[i];

            if (newX >= 0 && newX < arr.length && newY >= 0 && newY < arr[0].length && !visited[newX][newY]
                    && arr[newX][newY] != '0') {
                qNodes.add(new QNode(newX, newY, currDistance + 1));
            }
        }

    }

    return -1;
}

private static class QNode {
    int x;
    int y;
    int distance;

    QNode(int x, int y, int distance) {
        this.x = x;
        this.y = y;
        this.distance = distance;
    }
}

In this example by input is:

0001110011
1111011110
0110001010
S010101011
1110111E01

[3,0] is my starting point and [4,7] is my destination with value E

The above code prints 16 as shortest path. But I want to print the actual path like this if present or not exists if not possible to reach destination.

Expected output for above code:

000***0011
11**0**110
01*000*010
S0*010*011
***011*E01

Here I want to print the matrix again with valid path route with * . How to achieve this in my code or is there a better approach to solve this?

You could have a field called prev in your class QNode to track the previous node it visited and when you finished the search, you can track your path by following the prev link.

The code would be :

  private static Queue<QNode> qNodes;
  private static QNode endNode;
  public static void main(String[] args) {
    char[][] M = new char[][] { "0001110011".toCharArray(), "1111011110".toCharArray(),
            "0110001010".toCharArray(), "S010101011".toCharArray(), "1110111E01".toCharArray() };
    int r = findShortestPathBFS(M, 3, 0);
    while ( endNode.prev != null && M[endNode.prev.x][endNode.prev.y] != 'S') {
       M[endNode.prev.x][endNode.prev.y] = '*';
       endNode = endNode.prev;
    }
    for ( char[] arr : M )
      System.out.println(Arrays.toString(arr));
  }

  private static int findShortestPathBFS(char arr[][], int startX, int startY) {
      if (arr[startX][startY] == 'E')
          return 0;
      int moveX[] = new int[] { 0, 0, 1, -1 };
      int moveY[] = new int[] { 1, -1, 0, 0 };
      boolean visited[][] = new boolean[arr.length][arr[0].length];
      qNodes = new LinkedList<>();
      qNodes.add(new QNode(startX, startY, 0, null));
      while (!qNodes.isEmpty()) {
          QNode currNode = qNodes.remove();
          int currX = currNode.x;
          int currY = currNode.y;
          int currDistance = currNode.distance;
          visited[currX][currY] = true;
          // System.out.println(arr[currX][currY]);
          if (arr[currX][currY] == 'E') {
            endNode = currNode;
            return currDistance;
          }

          for (int i = 0; i < moveX.length; i++) {
              int newX = currX + moveX[i];
              int newY = currY + moveY[i];

              if (newX >= 0 && newX < arr.length && newY >= 0 && newY < arr[0].length && !visited[newX][newY]
                      && arr[newX][newY] != '0') {
                  qNodes.add(new QNode(newX, newY, currDistance + 1, currNode));
              }
          }
      }
      return -1;
  }
    
  private static class QNode {
      int x;
      int y;
      int distance;
      QNode prev;

      QNode(int x, int y, int distance, QNode prev) {
          this.x = x;
          this.y = y;
          this.distance = distance;
          this.prev = prev;
      }
  }

See that I moved the queue outside and used a node called endNode to track the well End Node, and then after search if that endNode is not null ie if it is found, follow through using its prev link until it is null. It would be null for the start node as you can see from the statement : qNodes.add(new QNode(startX, startY, 0, null));

Output is :

[0, 0, 0, *, *, *, 0, 0, 1, 1]
[1, 1, *, *, 0, *, *, 1, 1, 0]
[0, 1, *, 0, 0, 0, *, 0, 1, 0]
[S, 0, *, 0, 1, 0, *, 0, 1, 1]
[*, *, *, 0, 1, 1, *, E, 0, 1]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM