【问题标题】:stack overflow exception in recursion java递归java中的堆栈溢出异常
【发布时间】:2017-09-27 10:20:58
【问题描述】:

我的问题是当我在第 133 行将第一个参数更改为超过 300 时,我在第 37 行得到一个 java.lang.StackOverflowError。这一行是递归。我该如何解决这个问题?

public class PathFindingOnSquaredGrid {

// given an N-by-N matrix of open cells, return an N-by-N matrix
// of cells reachable from the top
public static boolean[][] flow(boolean[][] open) {
    int N = open.length;

    boolean[][] full = new boolean[N][N];
    for (int j = 0; j < N; j++) {
        flow(open, full, 0, j);
    }

    return full;
}

 // determine set of open/blocked cells using depth first search
 public static void flow(boolean[][] open, boolean[][] full, int i, int j) {
    int N = open.length;

    // base cases
    if (i < 0 || i >= N) return;    // invalid row
    if (j < 0 || j >= N) return;    // invalid column
    if (!open[i][j]) return;        // not an open cell
    if (full[i][j]) return;         // already marked as open

    full[i][j] = true;

    flow(open, full, i+1, j);   // down line 37
    flow(open, full, i, j+1);   // right line 38
    flow(open, full, i, j-1);   // left line 39
    flow(open, full, i-1, j);   // up line 40
}

// does the system percolate?
public static boolean percolates(boolean[][] open) {
    int N = open.length;

    boolean[][] full = flow(open);
    for (int j = 0; j < N; j++) {
        if (full[N-1][j]) return true;
    }

    return false;
}

//does the system percolate vertically in a direct way?
public static boolean percolatesDirect(boolean[][] open) {
    int N = open.length;

    boolean[][] full = flow(open);
    int directPerc = 0;
    for (int j = 0; j < N; j++) {
        if (full[N-1][j]) {
            // StdOut.println("Hello");
            directPerc = 1;
            int rowabove = N-2;
            for (int i = rowabove; i >= 0; i--) {
                if (full[i][j]) {
                     //StdOut.println("i: " + i + " j: " + j + " " + full[i][j]);
                    directPerc++;
                }
                else break;
            }
        }
    }

    // StdOut.println("Direct Percolation is: " + directPerc);
    if (directPerc == N) return true; 
    else return false;
}

// draw the N-by-N boolean matrix to standard draw
public static void show(boolean[][] a, boolean which) {
    int N = a.length;
    StdDraw.setXscale(-1, N);;
    StdDraw.setYscale(-1, N);
    StdDraw.setPenColor(StdDraw.BLACK);
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            if (a[i][j] == which)
                StdDraw.square(j, N-i-1, .5);
            else StdDraw.filledSquare(j, N-i-1, .5);
}

// draw the N-by-N boolean matrix to standard draw, including the points A (x1, y1) and B (x2,y2) to be marked by a circle
public static void show(boolean[][] a, boolean which, int x1, int y1, int x2, int y2) {
    int N = a.length;
    StdDraw.setXscale(-1, N);;
    StdDraw.setYscale(-1, N);
    StdDraw.setPenColor(StdDraw.BLACK);
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            if (a[i][j] == which)
                if ((i == x1 && j == y1) ||(i == x2 && j == y2)) {
                    StdDraw.circle(j, N-i-1, .5);

                }
                else StdDraw.square(j, N-i-1, .5);
            else StdDraw.filledSquare(j, N-i-1, .5);
}

// return a random N-by-N boolean matrix, where each entry is
// true with probability p
public static boolean[][] random(int N, double p) {
    boolean[][] a = new boolean[N][N];
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            a[i][j] = StdRandom.bernoulli(p);
    return a;
}



// test client
public static void main(String[] args) {

    ArrayList<Node> path=null;
    Stopwatch timer;


   // The following will generate a 10x10 squared grid with relatively few 
   obstacles in it
   //The lower the second parameter, the more obstacles (black cells) are 
   generated

在这里,我正在更改网格值以获取测试用例。

    boolean[][] randomlyGenMatrix = random(350, 0.8); //line133

    StdArrayIO.print(randomlyGenMatrix);
    show(randomlyGenMatrix, true);

    System.out.println();
    //System.out.println("The system percolates: " + percolates(randomlyGenMatrix));

    System.out.println();
    //System.out.println("The system percolates directly: " + percolatesDirect(randomlyGenMatrix));
    System.out.println();


    Stopwatch timerFlow = new Stopwatch();

    Scanner in = new Scanner(System.in);
    System.out.println("Enter i for A > ");
    int Ai = in.nextInt();

    System.out.println("Enter j for A > ");
    int Aj = in.nextInt();

    System.out.println("Enter i for B > ");
    int Bi = in.nextInt();

    System.out.println("Enter j for B > ");
    int Bj = in.nextInt();


 // THIS IS AN EXAMPLE ONLY ON HOW TO USE THE JAVA INTERNAL WATCH
    // Stop the clock ticking in order to capture the time being spent on inputting the coordinates
    // You should position this command accordingly in order to perform the algorithmic analysis
    StdOut.println("Elapsed time = " + timerFlow.elapsedTime());

            //StdDraw.point(Ai, Bj);           

    // System.out.println("Coordinates for A: [" + Ai + "," + Aj + "]");
    // System.out.println("Coordinates for B: [" + Bi + "," + Bj + "]");

    show(randomlyGenMatrix, true, Ai, Aj, Bi, Bj);


     String dis="";
     while(!dis.equalsIgnoreCase("X")){
        //Selecting the path
        System.out.println("Enter Distance: (M)Manhattan|(E)Euclidean|(C)Chebyshev|(X)Exit");         
        dis=in.next();
        timer=new Stopwatch();
        path = new DijkstraAlgorithm(dis).distance(randomlyGenMatrix, Ai, Aj, Bi, Bj);

        System.out.println("Elapsed time: "+timer.elapsedTime());

        //Draw the path in the grid
        for (Node node : path) {
            StdDraw.filledCircle(node.y, 10 - node.x -1, .2);


        }
  }
    System.exit(0);

}

}

【问题讨论】:

  • 如果您更改代码以使用更少的递归,您可以解决它 - 这是任何人都可以解决这些问题的唯一方法。可以选择增加调用堆栈的长度,但这只会使异常稍后发生。
  • 每个方法调用都需要一些堆栈空间。您的递归代码似乎没问题(您检查您是否使用if (full[i][j]) return; full[i][j] = true; 代码获得无限递归);似乎只是将它与一个太大的参数一起使用,所有递归调用都无法适应。

标签: java recursion stack-overflow


【解决方案1】:

您使用递归的唯一目的是跟踪需要检查的位置。因此,您可以改为拥有这些位置的队列,并继续处理从队列头部弹出的位置,直到队列为空。循环的主体看起来像 flow 方法的主体(除了初始测试将 continue 循环而不是 returning),但您将使用初始 (i,j) 位置初始化队列,并将递归调用替换为这些位置的入队。

【讨论】:

    猜你喜欢
    • 2016-02-19
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2016-12-30
    • 2020-07-13
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多