Java:难以理解递归方法调用

时间:2018-10-17 23:01:12

标签: java recursion methods

我希望你们都过得愉快。

我的老师把裤子弄乱了。我已经读过书并进行了研究,但仍然感到困惑。我现在正在学习方法,所以我还有很长的路要走。我制作了一个类似“俄勒冈足迹”的游戏,它使用“游戏结束”方法询问用户是否要再次玩。

主要问题: 我的老师提到了一个模糊的问题,即游戏是否循环了足够多的时间,最终导致了stackOverflow。这对我来说很有意义,因为游戏继续以我拥有的方式将方法嵌套在彼此内部,每次调用“新游戏”方法都将其添加到堆栈中,因为外部方法仍然在那里等待完成。 / p>

我列举了一个我的意思的例子。假设存在用户输入的停顿之类的问题,那么当我在其他方法中调用方法时,如何确保我的内存使用率不会持续增长?我认为这个词是“递归的”,因此是我的标题。

请,如果有人可以推荐一个好的形式来处理这个问题,我将非常感激。

public class Testing
{
    public static void main(String[] args) {
        System.out.println("main method");
        gameStart();
    }

    private static void gameStart()
    {
        System.out.println("some other method called");
        gameOver();
    }

    private static void gameOver()
    {
        System.out.println("game over called"); //I would ask the user if they want to play again.
        //keeping it concise to illustrate my point, instead of using an if statement
        gameStart();//starting the cycle I'm concerned about. Assume the user indicated they would like to play again.
    }
}

3 个答案:

答案 0 :(得分:2)

递归需要一个条件,该条件将继续调用。
递归是最常见的方法调用自身的地方,例如计算斐波那契数列,其中

fib(n) == fib(n-1) + fib(n-2)

fib(0)被定义为0,因此您不必进行计算。
fib(1)被定义为1,因此您不必进行计算。
其他每个数字都是通过fib()方法调用自己的两次来计算的,但是对于两个没有定义可计算的情况,它避免了递归调用。用伪代码

int fib(int n)
{
    if (n == 0) return 0; // doesnt have to recursively call
    if (n == 1) return 1; // same
    return fib(n-1) + fib(n-2);
}

在您的情况下,您有两个方法分别调用彼此,但是您没有条件可以从中逃脱这些调用。

一种可能性是,gameOver()仅在游戏以平局结束时才呼叫gameStart(),例如

public class Testing
{
    public static void main(String[] args) {
        System.out.println("main method");
        gameStart();
    }

    private static void gameStart()
    {
        System.out.println("some other method called");
        gameOver();
    }

    private static void gameOver()
    {
        System.out.println("game over called");
        if (gameTied()) {
            gameStart();
        }
    }
}

如果您只是问“您想再玩一次吗?” -最好在main中按照

public static void main(String[] args) {
    System.out.println("main method");
    String playGame = "Yes";
    while (playGame.equalsIgnoreCase("Yes") {
        gameStart();
        playGame = ask("Play again?");
    }
}

答案 1 :(得分:2)

为避免无限递归,您可以切换到迭代并为当前决定如何进行(目前是通过直接调用相应的动作)的那些方法引入返回值。 让这些方法返回一些符号,下一步,例如使用枚举。 然后编写一个循环,根据返回值调用正确的方法。

示例(缩写,假设您知道Java语法):

enum Action { Start, ShowEnd, Quit }

主要:

Action nextAction = Action.Start;
while (action != Action.Quit)
{
    switch (action)
    {
        case Start:
            nextAction = gameStart();
            break;
        case ShowEnd:
            nextAction = gameEnd();
            break;
        // ToDo: write more actions!
        default:
            break;
    }
}

假设每个此类方法都将执行,直到决定下一步采取何种行动为止。

这样,您的调用堆栈将一直很平坦,因为执行总是返回到main方法,然后分支到其他方法。

答案 2 :(得分:1)

编写递归代码时,应确保具有某种结束条件,否则将再次调用该函数。例如,我使用gameOverif(gamePlayedThisManyTimes <= 1) return;方法添加了结束条件。运行以下代码时,为方法gameStart提供的值将确定您玩了多少游戏,而gameOver会在调用“ gameStart”时递减该值,以最终达到递归的结束条件。

public static void main(String[] args)
{
    System.out.println("main method");
    gameStart(10);
}

private static void gameStart(int playGameThisManyTimes)
{
    System.out.println("Game " + playGameThisManyTimes + " started...");
    System.out.println("some other method called");
    gameOver(playGameThisManyTimes);
}

private static void gameOver(int gamePlayedThisManyTimes)
{
    System.out.println("game over called for " + gamePlayedThisManyTimes); //I would ask the user if they want to play again.

    if(gamePlayedThisManyTimes <= 1)
        return;
    else
        gameStart(gamePlayedThisManyTimes - 1);
}

输出

main method
Game 10 started...
some other method called
game over called for 10
Game 9 started...
some other method called
game over called for 9
Game 8 started...
some other method called
game over called for 8
Game 7 started...
some other method called
game over called for 7
Game 6 started...
some other method called
game over called for 6
Game 5 started...
some other method called
game over called for 5
Game 4 started...
some other method called
game over called for 4
Game 3 started...
some other method called
game over called for 3
Game 2 started...
some other method called
game over called for 2
Game 1 started...
some other method called
game over called for 1