繁体   English   中英

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

[英]Java: trouble understanding recursive method calling

我制作了一个类似“俄勒冈小道”的游戏,它使用“游戏结束”的方法来询问用户是否想再玩一次。

主要问题:我的老师提到了一些关于如果游戏循环次数足够多的话,我们最终会出现 stackOverflow 的情况。 这对我来说很有意义,因为游戏继续按照我的方式将方法嵌套在彼此内部,每次调用“新游戏”方法时都会添加到堆栈中,因为外部方法仍在那里等待完成。

我已经总结了一个例子来说明我的意思。 假设用户输入等有暂停,我应该如何确保我的内存利用率不会在我调用其他方法中的方法时继续增长? 我认为这个词是“递归的”,因此是我的标题。

如果有人可以推荐正确的形式来处理这个问题,我将不胜感激。

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.
    }
}

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

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?");
    }
}

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

示例(缩写,我假设您知道 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 方法,然后分支到其他方法。

当您编写递归代码时,您应该确保除了再次调用该函数之外还有某种结束条件。 例如,我为gameOver方法添加了一个结束条件if(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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM