我希望你们都过得愉快。
我的老师把裤子弄乱了。我已经读过书并进行了研究,但仍然感到困惑。我现在正在学习方法,所以我还有很长的路要走。我制作了一个类似“俄勒冈足迹”的游戏,它使用“游戏结束”方法询问用户是否要再次玩。
主要问题: 我的老师提到了一个模糊的问题,即游戏是否循环了足够多的时间,最终导致了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.
}
}
答案 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)
编写递归代码时,应确保具有某种结束条件,否则将再次调用该函数。例如,我使用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