Java 计数器从1开始时递归方法上的堆栈溢出

Java 计数器从1开始时递归方法上的堆栈溢出,java,recursion,Java,Recursion,我编写了一个程序来读取包含1和0矩阵的文本文件,该矩阵将递归地循环以识别所有唯一的四个连接区域(通过上、下、左、右移动连接的区域)。然后,我用一个标识符编号替换每个区域中的1,但是,当我将替换值的计数器设置为1时,会出现堆栈溢出错误。在构建递归方法时,我已经解决了这个问题,从2开始,然后在完成所有操作后返回,并将所有区域值减1,以便区域计数器在输出中从1开始。这是可行的,我的输出是正确的,但这感觉像是一个懒惰的解决方案 我知道我需要一种方法来识别1是否已经被识别,这将允许我用1s替换一个区域,并

我编写了一个程序来读取包含1和0矩阵的文本文件,该矩阵将递归地循环以识别所有唯一的四个连接区域(通过上、下、左、右移动连接的区域)。然后,我用一个标识符编号替换每个区域中的1,但是,当我将替换值的计数器设置为1时,会出现堆栈溢出错误。在构建递归方法时,我已经解决了这个问题,从2开始,然后在完成所有操作后返回,并将所有区域值减1,以便区域计数器在输出中从1开始。这是可行的,我的输出是正确的,但这感觉像是一个懒惰的解决方案

我知道我需要一种方法来识别1是否已经被识别,这将允许我用1s替换一个区域,并且仍然能够正确地读取网格,但是我不确定是否有任何方法可以查看元素是否是对象的成员。我试图构建一系列if-else语句来识别遇到的第一个1并从那里循环,但是当我再次命中该区域时,我要么得到堆栈溢出错误,要么得到奇怪的输出,例如第一个区域中的每个数字(应该用新的1代替)都是不同的数字。编写第二个递归方法来处理遇到的第一个1会更聪明吗?还是我从2开始,然后再递减所有值,这真的让程序很难看

/**
 * Scans the grid for 1s, calling the designateRegions method when unique
 * 1s are found.
 */
public static void findRegions() {
    int region = 2;//the counter variable in question
    for (int i = 0; i < nRows; i++) {
        for (int j = 0; j < nCols; j++) {
            if (grid[i][j] == 1) {
                //Ensure the value isn't part of a known region
                if (j-1 >= 0 && grid[i][j-1] >= 1) {
                    grid[i][j] = grid[i][j-1];
                } else if (i-1 >= 0 && grid[i-1][j] >= 1) {
                    grid[i][j] = grid[i-1][j];
                } else {//if 1 is unique
                    Regions regionObject = new Regions(region);//instantiate a Regions object
                    regionCountList.add(regionObject);//add new Regions object to arraylist
                    designateRegions(grid, i, j, region, regionObject);//call recursive method designateRegions
                    region++;
                }//end nested if-else block
            }//end outer if statement
        }//end inner for loop
    }//end outer for loop

    //this is stupid
    for (int i = 0; i < nRows; i++) {
        for (int j = 0; j < nCols; j++) {
            if (grid[i][j] > 1) {
                grid[i][j] = grid[i][j] - 1;//drop the value of each region by 1
            }//end if statement
        }//end inner for loop
    }//end outer for loop

}//end findRegions method

/**
 * Loops recursively to identify four-connected regions of 1s and change the
 * value of the elements in the newly identified region.
 * @param grid the 2d integer array containing the grid to be scanned
 * @param r the row position
 * @param c the column position
 * @param region the identifier value for the region
 * @param regionObject the object associated with each region
 */
private static void designateRegions(Integer[][] grid, int r, int c, int region, Regions regionObject) {
    if (grid[r][c] == 0) { //base case
    } else if (grid[r][c] == 1) {
        grid[r][c] = region;//switch value of the 1 with appropriate region identifier
        regionObject.regionCount++;
        if (r - 1 >= 0) {
            designateRegions(grid, r - 1, c, region, regionObject);//move up
        }
        if ((r + 1) < nRows) {
            designateRegions(grid, r + 1, c, region, regionObject);//move down
        }
        if ((c + 1) < nCols) {
            designateRegions(grid, r, c + 1, region, regionObject);//move right
        }
        if (c - 1 >= 0) {
            designateRegions(grid, r, c - 1, region, regionObject);//move left
        }
    }
}//end findRegions method
/**
*扫描网格1s,在唯一时调用designateRegions方法
*找到1。
*/
公共静态void findRegions(){
int region=2;//所讨论的计数器变量
对于(int i=0;i=0&&grid[i][j-1]>=1){
网格[i][j]=网格[i][j-1];
}else如果(i-1>=0&&grid[i-1][j]>=1){
网格[i][j]=网格[i-1][j];
}else{//如果1是唯一的
Regions regionObject=新区域(region);//实例化区域对象
regionCountList.add(regionObject);//将新区域对象添加到arraylist
指定区域(网格、i、j、区域、区域对象);//调用递归方法指定区域
区域++;
}//结束嵌套的if-else块
}//结束外部if语句
}//内环端
}//外循环结束
//这太愚蠢了
对于(int i=0;i1){
grid[i][j]=grid[i][j]-1;//将每个区域的值减1
}//end if语句
}//内环端
}//外循环结束
}//端点区域法
/**
*递归循环,以标识1的四个连接区域,并更改
*新标识区域中元素的值。
*@param grid包含要扫描的网格的二维整数数组
*@param r行位置
*@param c表示柱位置
*@param region区域的标识符值
*@param regionObject与每个区域关联的对象
*/
专用静态void designateRegions(整数[][]网格、int r、int c、int region、Regions regionObject){
如果(grid[r][c]==0){//基本情况
}else if(网格[r][c]==1){
grid[r][c]=region;//使用适当的区域标识符切换1的值
regionObject.regionCount++;
如果(r-1>=0){
指定区域(网格、r-1、c、区域、区域对象);//向上移动
}
如果((r+1)=0){
指定区域(栅格、r、c-1、区域、区域对象);//向左移动
}
}
}//端点区域法

您正确地识别了问题:递归代码需要标记已访问的每个网格元素,以防止程序追尾

使用不同的值(2)标记访问的单元格是一种有效的策略。另一种可能是传递一个单独的
boolean[nRows][ncol]
s网格,其中包含
true
的单元格用于标识访问的单元格


我认为您的解决方案更干净,因为它不需要分配任何额外的内存。

我不理解所有这些结束投票。问题非常具体,它讨论了一种标记访问单元的技术,并且它有一个工作代码(当OP尝试重构代码时会发生堆栈溢出)。我无法想象如何区分标识第一个区域的1和标识原始单元的1。但这样的问题最好在CodeReview上提出。@dasblinkenlight您是对的,它非常具体。不幸的是,这个问题的措辞会引起争论,而不是基于事实的答案。通常,当你用“它会更聪明吗?”这样的措辞提问时,这是一个警告标志。我投票决定结束,直到它以一种不那么基于意见的方式重新措辞……那么我的方法有效吗?我想人们会鄙视它。第二个网格是一个我从未想过的伟大解决方案,但内存和时间使用可能会是一个问题,正如您所说的(这是针对数据结构类的,所有内容都与我的教授的时间复杂性有关)。如果这是一个诚实的方法,我可以保留它。我只是想人们不会喜欢我做的。顺便说一句,谢谢你的帮助。我真的很感激。