【问题标题】:How can one get rid of previous iteration of recursive method call?如何摆脱递归方法调用的先前迭代?
【发布时间】:2017-12-19 03:43:02
【问题描述】:

我有一个方法可以检查用户输入的值是否在数组范围内:

public static void placeMove(int num1, int num2){
    //checking if x and y are  greater than rows and columns of a 2D array
    if(num1 > rows-1 || num2 > columns-1){
      System.out.println("This space is off the board, try again.");
      int[] values = new int[2];
      values = inputMove(); //calls inputMove method to ask user for new input
      placeMove(values[0],values[1]); //calling itself to check 
                                     //if new values are prohibited
    }
    //code to place a value in grid[num1][num2]
}

我有一个二维数组(行和列的大小取决于设置):

char[][] grid = new char[rows][columns];

当我错误检查 num1/num2 是否大于它们各自的行/列时,我的 placeMove 方法给了我一个 ArrayIndexOutOfBoundsException。 placeMove 再次调用 placeMove 并将第一次调用 placeMove 的状态保存在堆栈中,一旦执行完对 placeMove 的第二次调用,则第一次迭代将使用堆栈中保存的局部变量的值恢复其进一步执行,并且导致异常。我该如何防止这种情况?感谢您的帮助!

【问题讨论】:

  • @JBNizet 我知道为什么会发生错误,我正在尝试处理可能通过要求他们输入新动作来输入脱离网格的动作的用户,但是一旦他们添加了新动作移动,上一次调用离网移动的函数会执行并导致异常。

标签: java recursion static stack procedural


【解决方案1】:

非常简单:只需 return 来自递归调用后的函数 - 或将其他代码放入 else 块中:

    placeMove(values[0],values[1]);
    return; // <--
}
//code to place a value in grid[num1][num2]

或者:

    placeMove(values[0],values[1]);
}
else
{
    //code to place a value in grid[num1][num2]
}

实际上,虽然不需要递归调用,您可以使用循环来代替:

while(num1 >= rows || num2 >= columns)
// ^ instead of if         ^ (additionally changed comparison)
{
     System.out.println("This space is off the board, try again.");
     int[] values = inputMove();
     //           ^  can assign directly,
     //              (the array you created previously is just GC'ed)
     num1 = values[0];
     num2 = values[1];
}
//code to place a value in grid[num1][num2]

根据您的评论进行编辑:

我在 main 方法中分别调用了 inputMove() 然后 placeMove(int num1, int num2) 最后是 checkWin(int num1, int num2) 方法。 checkWin() 方法使用 inputMove() 方法返回的值。

那么你应该不调用inputMove within placeMove,而是:

int main(String[] args)
{
    int[] values = inputMove();
    while(values[0] >= rows || values[1] >= columns)
    // by the way: you do not check for NEGATIVE input!!!
    {
        System.out.println("This space is off the board, try again.");
        values = inputMove();
    }
    placeMove(values[0], values[1]); // <- won't read input any more!
    checkWin(values[0], values[1]);
}

其实这倒应该是一个新问题,下次更喜欢这样做,最好是参考当前问题...

Edit2:实际上,正常检查输入是获取输入的一部分,所以我的建议是将while循环移到inputMove:

int[] inputMove()
{
    int[] values = new int[2];
    for(;;)
    {
        // read only ROW as before
        if(0 <= values[0] && values[0] < rows)
            break;
        System.out.println("row out of range");
    }
    // now the same for COLUMN
    return values;
}

Main 现在只删除 while 循环:

int main(String[] args)
{
    int[] values = inputMove();
    placeMove(values[0], values[1]); // <- won't read input any more!
    checkWin(values[0], values[1]);
}

通过这种方式,您可以清楚地将彼此最密切相关的内容归为一类。此外,对于行和列,使用两个单独的循环,如果仅列无效,您不会强制用户重新输入行...

【讨论】:

  • 这真的很有帮助,我试过了,我意识到我还有另一种方法,它使用 inputMove() 方法中的值来检查用户是否赢了。所以我需要 placeMove 方法中的更改值才能继续执行程序。我的程序真的到处都是。
  • @splash 你的意思是你想在不提供新值的情况下再次重用最新的输入吗?如果是这样,您需要在某处缓冲最新输入...
  • 是的,我在 main 方法中分别调用了 inputMove() 然后 placeMove(int num1, int num2) 最后是 checkWin(int num1, int num2) 方法。 checkWin() 方法使用从 inputMove() 方法返回的值。我不知道如何将新值从 placeMove 发送到 checkWin。
  • 我明白了,只是在我的 placeMove 方法中添加了一个返回值,一切都好起来了!非常感谢您的帮助
  • 哇,你的编辑是一种更聪明的方式,我现在觉得很笨,哈哈!谢谢人
猜你喜欢
  • 2021-09-28
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 2020-06-25
  • 2021-12-24
  • 2014-10-13
相关资源
最近更新 更多