Java自调用函数中的堆栈溢出错误(孤岛数)

时间:2018-10-30 01:40:26

标签: java recursion count self gaps-and-islands

我对导致堆栈溢出错误的原因进行了一些研究,我可以得出结论,这是由程序中的一个递归函数引起的,该程序应该“计算数组中的孤岛数”。我了解导致问题的原因,但不确定为什么会发生此问题,或者我的主要问题是如何实际解决此问题。我发现,如果我通过反复在控制台上打印一些东西来减慢该程序的速度,则它可以工作,但要花很长时间才能完成。有没有一种方法可以保持程序速度而不出错,还是有更好的方法来解决问题(搜索“孤岛数”以查找问题)。而且,该数组是二维的,大小为1050 x 800。

public class NumOfIslands {
  static boolean[][] dotMap = new boolean[1050][800];
  static boolean visited[][] = new boolean[1050][800];
  static int total = 0;
  public static void main(String args[]) {
    defineArrays();
    run();
  }
  public static void findObjects(int xCord, int yCord) {
    for(int y = yCord - 1; y <= yCord + 1; y++) {
      for(int x = xCord - 1; x <= xCord + 1; x++) {
        if(x > -1 && y > -1 && x < dotMap[0].length && y < dotMap.length) {
          if((x != xCord || y != yCord) && dotMap[x][y] == true && visited[x][y] != true) {
            visited[x][y] = true;
            findObjects(x,y);
            //System.out.println("test");
          }
        }
      }
    }
  }
  public static void defineArrays() {
    for(int y = 0; y < 800; y++) {
      for(int x = 0; x < 1050; x++) {
        dotMap[x][y] = true;
      }
    }
  }

  public static int run() {
    //dotMap = DisplayImage.isYellow;
    System.out.println(dotMap.length + " " + dotMap[0].length);
    int objects = 0;
    for(int y = 439; y < 560/*dotMap[0].length*/; y++) {
      for(int x = 70; x < 300/*dotMap.length*/; x++) {
        if(dotMap[x][y] == true && visited[x][y] != true) {
          visited[x][y] = true;
          objects++;
          findObjects(x,y);
        }
      }
    }
    System.out.println("total" + total);
    System.out.println(objects);
    return objects;

  }
}

2 个答案:

答案 0 :(得分:1)

StackOverflowError reasons。在您的示例中,每次对findObjects的调用都会从循环中向堆栈int x和int y添加2个变量。


最快的解决方案之一:

class Solution {
    int m, n;
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }
        m = grid.length;
        n = grid[0].length;
        int counter = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    visit(grid, i, j);
                    counter++;
                }
            }
        }
        return counter;
    }

    public void visit(char[][] grid, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) {
            return;
        }
        if (grid[i][j] == '0') {
            return;
        }
        grid[i][j] = '0';
        visit(grid, i - 1, j);
        visit(grid, i + 1, j);
        visit(grid, i, j - 1);
        visit(grid, i, j + 1);
    }
}

所有递归算法都可以使用循环来实现。下面是示例之一。该解决方案实现了BFS(广度优先搜索)算法,有关wikipedia的更多详细信息。

class Solution {
  public int numIslands(char[][] grid) {
    if (grid == null || grid.length == 0) {
      return 0;
    }

    int nr = grid.length;
    int nc = grid[0].length;
    int num_islands = 0;

    for (int r = 0; r < nr; ++r) {
      for (int c = 0; c < nc; ++c) {
        if (grid[r][c] == '1') {
          ++num_islands;
          grid[r][c] = '0'; // mark as visited
          Queue<Integer> neighbors = new LinkedList<>();
          neighbors.add(r * nc + c);
          while (!neighbors.isEmpty()) {
            int id = neighbors.remove();
            int row = id / nc;
            int col = id % nc;
            if (row - 1 >= 0 && grid[row-1][col] == '1') {
              neighbors.add((row-1) * nc + col);
              grid[row-1][col] = '0';
            }
            if (row + 1 < nr && grid[row+1][col] == '1') {
              neighbors.add((row+1) * nc + col);
              grid[row+1][col] = '0';
            }
            if (col - 1 >= 0 && grid[row][col-1] == '1') {
              neighbors.add(row * nc + col-1);
              grid[row][col-1] = '0';
            }
            if (col + 1 < nc && grid[row][col+1] == '1') {
              neighbors.add(row * nc + col+1);
              grid[row][col+1] = '0';
            }
          }
        }
      }
    }
    return num_islands;
  }
}

答案 1 :(得分:0)

问题出在此功能

public static void findObjects(int xCord, int yCord) {


        for(int y = yCord - 1; y <= yCord + 1; y++) {
          for(int x = xCord - 1; x <= xCord + 1; x++) {
            if(x > -1 && y > -1 && x < dotMap[0].length && y < dotMap.length) {
              if((x != xCord || y != yCord) && dotMap[x][y] == true && visited[x][y] != true) {
                visited[x][y] = true;
                 findObjects(x,y);
                //System.out.println("test");
              }
            }
          }
        }
      }`

在这里,您构建了对 findobjects 的递归调用堆栈,最终它没有终止条件,所以最终以无限个 findobjects 堆栈结束,所以我的解决方案是如果您只是检查x和y的变量是否相等且访问的[x] [y]不为真,则无需调用递归,只需注释一下递归调用即可,因为您的循环已经完成了您想要的递归操作打电话去做。

 public static void findObjects(int xCord, int yCord) {


        for(int y = yCord - 1; y <= yCord + 1; y++) {
          for(int x = xCord - 1; x <= xCord + 1; x++) {
            if(x > -1 && y > -1 && x < dotMap[0].length && y < dotMap.length) {
              if((x != xCord || y != yCord) && dotMap[x][y] == true && visited[x][y] != true) {
                visited[x][y] = true;
                //findObjects(x,y);
                //System.out.println("test");
              }
            }
          }
        }
      }