Рекурсивная функция-Java

#java #algorithm #recursion #methods

#java #алгоритм #рекурсия #методы

Вопрос:

Может кто-нибудь объяснить, что происходит в этом коде. Код завершается только при передаче -1. До этого он продолжает запрашивать ввод данных пользователем. И только после завершения он выводит значения, кратные 3, из входных значений. Я в замешательстве, где все значения x сохраняются до завершения.

 
public class Recursion {
    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        multipleThree(in);


    }//end of main
    public static  void multipleThree(Scanner in) {
        
        System.out.println("Enter the list(-1 to terminate):");
        int x = in.nextInt();
        if (x == -1) {
            return;
        } else {
            multipleThree(in);
            if (x % 3 == 0)
                System.out.println(x   " is divisible by 3");

        }//end of else
      }//end of method
    }//end of class

 

Комментарии:

1. каждый раз, когда вызывается метод, некоторая память резервируется для его переменных и параметров (часто называемых фреймом) — поэтому каждый вызов имеет свою собственную версию переменных — поскольку int x объявляется переменная внутри метода, она сохраняется в этой памяти (фрейме). Не только актуально для рекурсивных вызовов, но и является ключевым для работы рекурсивных методов. [поскольку вывод выполняется после вызова to multipleThree , он будет выполнен только после возврата вызовов]

Ответ №1:

Я в замешательстве, где все значения x сохраняются до завершения.

Они хранятся в стеке вызовов.

В начале стек вызовов имеет только main . Затем main вызывает multipleThree . Это помещает новый фрейм в стек вызовов. Фрейм будет хранить информацию о том, куда продвинулся этот вызов multipleThree , какие существуют локальные переменные и т.д.

Допустим, вы ввели 3. x , который хранится во фрейме, который в настоящее время является вершиной стека. else Ветвь выполняется и multipleThree вызывается снова, поэтому новый фрейм помещается в стек вызовов. Обратите внимание, что мы еще не закончили с первым вызовом multipleThree . Мы можем вернуться к нему, когда закончим выполнение этого второго вызова multipleThree . Помните, что введенные вами 3 все еще хранятся в стеке вызовов.

Допустим, далее вы ввели 5, происходит то же самое — число 5 сохраняется в верхней части стека, затем при повторном вызове запускается новый кадр multipleThree (теперь это уже третий раз).

Наконец, вы вводите -1. На данный момент стек выглядит следующим образом:

 multipleThree (x = -1)
multipleThree (x = 5)
multipleThree (x = 3)
main
 

Вы можете увидеть это в отладчике в вашей IDE. например, в IntelliJ IDEA

введите описание изображения здесь

Поскольку вы ввели -1, этот вызов multipleThree фактически завершается, поскольку он достигает return оператора. Теперь открывается верхняя часть стека, и мы возвращаемся к выполнению второго вызова multipleThree . Теперь стек выглядит так:

 multipleThree (x = 5)
multipleThree (x = 3)
main
 

Во втором вызове помните, что x равно 5 — не делится на 3, поэтому мы ничего не делаем. Теперь мы закончили со вторым вызовом multipleThree , поэтому стек снова открывается:

 multipleThree (x = 3)
main
 

Теперь мы, наконец, возвращаемся к выполнению первого вызова multipleThree , когда x равно 3 . 3 делится на 3, поэтому мы его печатаем. Теперь мы закончили с первым вызовом multipleThree , поэтому мы также удаляем его из стека.