Как исправить ошибку переполнения стека? - PullRequest
2 голосов
/ 17 декабря 2009

Итак, у меня есть довольно хороший код для решения судоку в Java, но мне нужна помощь с этим методом. Это дает мне переполнение стека, когда я встраиваю его в основной метод. Проблема в том, что мой метод не знает, как развернуться и исправить свои ошибки. Мне нужен логический флаг (тот, который, в отличие от того, который используется в приведенном ниже коде, на самом деле работает лучше) или что-то, чтобы он знал, когда он должен повернуть назад и когда он снова может идти вперед и продолжать решать игру. Спасибо за любую помощь, вы можете дать

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)*/
        }       
    }
    }
}
}

Ответы [ 7 ]

24 голосов
/ 17 декабря 2009

Вместо того, чтобы решить это за вас, я хотел бы сделать несколько советов, как справиться с этим. 9 часов вполне достаточно.

1) Ваш код трудно читать. Попробуй немного разнести. Дайте своим переменным значимые имена, которые понятны (это поможет вам и другим людям читать ваш код). Возможно, вы допустили простую ошибку, и чистый код облегчит их обнаружение. Попробуйте разбить его на более мелкие методы, поскольку это сделает его более читабельным и более понятным.

2) Переполнения стека возникают (как я полагаю), когда вы делаете слишком много вложенных вызовов методов и типичны для рекурсивного кода. Поэтому сделайте вашу рекурсию понятной. Убедитесь, что у вас есть базовый случай, который будет завершен.

Извините, что не даю вам "ответ", но так как это звучит как домашнее задание, я думаю, что есть большая ценность в том, чтобы научиться решать это самостоятельно. Надеюсь, что это справедливо.

3 голосов
/ 17 декабря 2009

Я думаю, что ваша проблема там, где у вас есть:

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

Это потому, что вы, кажется, не изменяете здесь ни одно состояние, и вы передаете те же значения, которые заставили вас прийти к этому шагу в первую очередь. Для меня это похоже на бесконечную рекурсию.

Также, пожалуйста, выровняйте свой код правильно, так как его слишком сложно прочитать, когда он не выровнен, и, возможно, предоставьте некоторые подсказки, что делают другие методы. Удачи!

1 голос
/ 17 декабря 2009

Вы рекурсивно вызываете play, никогда не возвращаясь, и похоже, что вы каждый раз инициализируете новый набор переменных в верхней части функции.

Попробуйте отделить инициализацию от рекурсивной части. Вы также должны иметь четкое условие завершения для завершения рекурсии, например, (if (isBoardFilled () == true)) return.

Также структурируйте его так, чтобы вы добавили номер на доску, проверили его на наличие ограничений и, если он прошел, добавьте еще один номер (рекурс) или вернитесь назад, удалив последний номер, и повторите попытку.

1 голос
/ 17 декабря 2009

Ваш код выбрасывает стек поверх исключения потока, потому что вы никогда не достигаете условия завершения, которое завершает вашу рекурсию, или, по крайней мере, вы не видите, что у вас есть условие завершения рекурсии при чтении кода.

Ваш код не очень хорошо структурирован, поэтому вам будет сложно отлаживать его. Попробуйте реструктурировать свой код, это поможет вам переосмыслить проблему. Также, пожалуйста, прокомментируйте свой код:)

0 голосов
/ 17 декабря 2009

Мне удалось быть более кратким и ясным, но это все равно не сработало ... Мне просто нужен толчок через край, и я свободен дома. Я вложил в этот проект так много потраченных часов:

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);
        }       
        }
    }
    }
}
0 голосов
/ 17 декабря 2009

Я согласен с Томом, но вот подсказка.

Нет условия и оператора возврата для завершения рекурсивных вызовов.

0 голосов
/ 17 декабря 2009

Я думаю, что вы вызываете play () рекурсивно. Попробуйте проверить, есть ли условие остановки вашего рекурсивного вызова.

...