Java 如何修复此堆栈溢出错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1919787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:25:50  来源:igfitidea点击:

How do I fix this stack overflow error?

javarecursionstack-overflowsudoku

提问by user233542

So I have what I think is pretty good code for a sudoku solver in java but I need some help with this method. It gives me a stack overflow when I embed it in a main method. The problem is that my method doesn't know how to turn around and fix its mistakes. I need a boolean flag (one that, unlike the one used in the code below, actually works preferably) or something to let it know when it should turn back and when it can again go forwards and continue solving the game. Thanks for any help you can give

所以我有我认为非常好的 Java 数独求解器代码,但我需要一些有关此方法的帮助。当我将它嵌入到 main 方法中时,它给了我一个堆栈溢出。问题是我的方法不知道如何扭转并修复它的错误。我需要一个布尔标志(一个与下面代码中使用的标志不同,实际上最好工作的标志)或其他东西来让它知道何时应该返回以及何时可以再次前进并继续解决游戏。谢谢你提供的所有帮助

public void play(int r, int c){//this method throws the StackOverflowError
    if(needAtLoc(r,c).size()==9){
        int num=1+generator.nextInt(9);
        setCell(r,c,num,this);

    if(c<8){
    System.out.println(this);///////////////
    play(r, c+1);
    }
    else{
    play(r+1, 0);
    }
}
else{
    if(needAtLoc(r,c).size()==0){//no possible moves THIS IS THE PROBLEM LINE!!!
    if(c>0){
        play(r, c-1);//play last cell, in column to left
    }
    else{
        if(r==0){
        play(r,c);//first square, so must play again (can't go back)
        }
        else{
        play(r-1, 8);/*first cell of row so must go to previous row and 
                   the end column*/
        }
    }
    }

    else{//if there are possible moves
    int num=needAtLoc(r,c).remove(generator.nextInt(needAtLoc(r,c).size()));
    setCell(r,c,num,this);//set the value of the cell
    System.out.println(this);//////////////
    if(r==8 && c==8){//the end of the cell has been reached so must end recursive call
        return;
    }
    else{
        if(c<8){
        play(r, c+1);//normal, next cell
        }
        else{
        play(r+1, 0);/*last cell in row so we go to next one 
                   in the first column ("return" button)*/
        }       
    }
    }
}
}

回答by Tom Duckering

Rather than solve this for you I would make a few suggestions in how to tackle this. 9 hours is ample.

我不会为您解决这个问题,而是就如何解决这个问题提出一些建议。9个小时足够了。

1) Your code is hard to read. Try to space it out a bit. Give your variables meaningful names that are clear (this helps you and other people read your code). You may have made a simple mistake and clean code will make these easier to spot. Try to break it into smaller methods since this will make it more readable and more maintainable.

1)你的代码很难阅读。试着把它隔开一点。给你的变量赋予清晰的有意义的名字(这有助于你和其他人阅读你的代码)。您可能犯了一个简单的错误,而干净的代码将使这些错误更容易被发现。尝试将其分解为更小的方法,因为这将使其更具可读性和可维护性。

2) Stack overflows are caused (generally I believe) when you make too many nested method calls and are typical in recursive code. Therefore make your recursion clear. Make sure you have a base case that will terminate.

2)当您进行太多嵌套方法调用时会导致堆栈溢出(通常我相信)并且在递归代码中很常见。因此,请明确您的递归。确保您有一个将终止的基本案例。

Sorry to not give you "the answer" but since this sounds like homework I think there's more value in learning how to solve this yourself. Hope that seems fair.

很抱歉没有给你“答案”,但因为这听起来像是家庭作业,我认为学习如何自己解决这个问题更有价值。希望这看起来很公平。

回答by tomkaith13

I think u are calling play() recursively .Try to check if there is a stopping condition to ur recursive call.

我认为您正在递归调用 play() 。尝试检查您的递归调用是否存在停止条件。

回答by Alvin

Your code is throwing stack over flow exception because you never reach a terminating condition that ends your recursion, or at least it is not obvious you to see you have a recursion terminating condition by reading your code.

您的代码正在抛出堆栈溢出异常,因为您永远不会达到结束递归的终止条件,或者至少通过阅读您的代码并不明显看到您有递归终止条件。

Your code is not well structure, hence you will have a hard time debugging it. Try to restructure your code, it will help you rethink the problem. Also, please comment your code :)

您的代码结构不佳,因此您将很难调试它。尝试重构您的代码,它将帮助您重新思考问题。另外,请评论您的代码:)

回答by ata

I agree with Tom, but here is a hint.

我同意汤姆的看法,但这里有一个提示。

There is no condition and return statement to end the recursive calls.

没有条件和返回语句来结束递归调用。

回答by Andrew

You are recursively calling play without ever returning and it looks as if you are initialising a new set of variables each time at the top of the function.

您递归地调用 play 而不返回,看起来好像每次都在函数顶部初始化一组新变量。

Try splitting out the initialisation from the recursive part. You also need a clear end condition to end the recursion e.g. (if(isBoardFilled()==true)) return.

尝试从递归部分中分离出初始化。您还需要一个明确的结束条件来结束递归,例如 (if(isBoardFilled()==true)) 返回。

Also structure it so that you add a number to the board, test it against the contraints and if it passes add another number (recurse) or backtrack by removing the last number and try again.

还要对它进行结构化,以便您向板上添加一个数字,根据约束对其进行测试,如果它通过添加另一个数字(递归)或通过删除最后一个数字回溯并重试。

回答by user233542

I've managed to be more concise and more clear but it still won't run... I just need a push over the edge and I'm home free. I've dumped so many wasted hours into this project:

我已经设法变得更简洁、更清晰,但它仍然无法运行......我只需要推动一下边缘,我就可以自由回家了。我在这个项目中浪费了很多时间:

public ArrayList<Integer> needAtLoc(int r, int c){
    int bc=c/3;//the column within the SudokuBoard
    int blc;

    /*The two posibilities for the column within each SudokuBlock:*/
    if(c>=0 && c<3) {
        blc=c;
    }
    else {
        blc=c%3;
    }
    int br=r/3; //the row within the SudokuBoard
    int blr;

    /*The two possiblities for the row within each SudokuBlock:*/
    if(r>=0 && r<3) {
        blr=r;
    } else {
        blr=r%3;
    }
    ArrayList<Integer> needR = new ArrayList<Integer>();
    needR=checkR(r);//
    needR.trimToSize();
    System.out.println(needR);//////////////
    ArrayList<Integer> needC=new ArrayList<Integer>();
    needC=checkC(c);
    needC.trimToSize();
    System.out.println(needC);/////////////
    ArrayList<Integer> needBl=new ArrayList<Integer>();
    needBl=this.board[br][bc].updateMissing(); //that method updates and returns an ArrayList
    needBl.trimToSize();
    ArrayList<Integer> poss=new ArrayList<Integer>();
    poss.clear();
    for(Integer e: needBl){
        if(needC.contains(e) && needR.contains(e)){
            poss.add(e);
        }
    }

    return poss;
}

//this method throws the StackOverflowError
public void play(int r, int c){
    int bc=c/3; //the column within the SudokuBoard
    int blc;
    /*The two posibilities for the column within each SudokuBlock:*/
    if(c>=0 && c<3) {
        blc=c;
    } else {
        blc=c%3;
    }
    int br=r/3; //the row within the SudokuBoard
    int blr;

    /*The two possiblities for the row within each SudokuBlock:*/
    if(r>=0 && r<3) {
        blr=r;
    } else {
        blr=r%3;
    }
    if(needAtLoc(r,c).size()==9){
        int num=1+generator.nextInt(9);
        this.board[br][bc].setValue(blr, blc, num);
        if(c<8){
            System.out.println(this);///////////////
            play(r, c+1);
        } else{
            play(r+1, 0);
        }
    } else{
        if(needAtLoc(r,c).size()==0){ //no possible moves
            if(c>0){
                bc=(c-1)/3;
                if(c>0 && c<4) {
                    blc=c-1;
                } else {
                blc = (c-1) % 3;
            }
        this.board[br][bc].setValue(blr, blc, 0);
        play(r, c-1);
    }
    else{
        blc=0;
        bc=0;
        if(r==0){
        blr=0;
        br=0;
        this.board[br][bc].setValue(blr, blc, 0);
        play(r,c);
        }
        else{
        br=(r-1)/3;
        if(r>0 && r<4) {blr=r-1;}
        else {blr=(r-1)%3;}
        this.board[br][bc].setValue(blr, blc, 0);
        play(r-1, 8);
        }
    }
    }

    else{//if there are possible moves
        int num=needAtLoc(r,c).remove(generator.nextInt(needAtLoc(r,c).size()));
        this.board[br][bc].setValue(blr, blc, num);
        System.out.println(this);//////////////
        if(r==8 && c==8){
        return;
        }
        else{
        if(c<8){
            play(r, c+1);
        }
        else{
            play(r+1, 0);
        }       
        }
    }
    }
}

回答by inkredibl

I think your problem is where you have:

我认为你的问题是你有:

if(r==0)
{
    play(r,c);//first square, so must play again (can't go back)
}

That's because you don't seem to modify any state here and you pass the same values in that made you come to this step in the first place. Seems like infinite recursion for me.

那是因为您似乎没有在这里修改任何状态,并且您传递了相同的值,这使您首先来到了这一步。对我来说似乎是无限递归。

Also please align your code correctly as it is too hard to read when it is misaligned and maybe provide some clues what the other methods do. Good luck!

另外请正确对齐您的代码,因为它在未对齐时很难阅读,并且可能提供一些其他方法的功能的线索。祝你好运!