Что приводит к сбою этой рекурсивной функции по сравнению с другой почти идентичной?
Это приводит к ошибке. Мне просто нужна помощь, объясняющая, почему это происходит с ошибкой по сравнению с правильным. Я использовал отладчик, но мне все еще не ясно.
public static void main(String[] args) {
countForwards(5);
}
public static void countForwards( int num ) {
if (num >= 0){
countForwards(num--);
}
System.out.print(num + " ");
}
Я знаю, что это решение, но я не понимаю, почему он отличается
public static void countForwards( int num ) {
if (num >= 0){
countForwards(num - 1);
}
System.out.print(num + " ");
}
Ответы
Ответ 1
countForwards(num--)
передает исходное значение num
в рекурсивный вызов, что означает, что рекурсия никогда не заканчивается.
countForwards(--num)
позволит завершить рекурсию.
После просмотра всего трафика, который получил этот вопрос, я подумал, что стоит немного расширить ответ.
Как прокомментировал paxdiablo, хотя countForwards(--num)
позволяет завершить рекурсию, он ведет себя иначе, чем countForwards(num-1)
.
Оба варианта приведут к следующей серии рекурсивных вызовов:
countForwards(5)
countForwards(4)
countForwards(3)
countForwards(2)
countForwards(1)
countForwards(0)
countForwards(-1)
но при повторной рекурсии они выведут другую серию чисел:
num - 1 --num
-1 -1
0 -1
1 0
2 1
3 2
4 3
5 4
Причина разницы в том, что num-1
не меняет значение num
, а --num
уменьшается num
.
Ответ 2
num--
использует постфиксный оператор --
, что означает, что передается исходное значение i.e. num
, а его значение уменьшено после его передачи.
Интересная вещь о постфиксном операторе, то есть том, который мы используем в этом примере, заключается в том, что операция выполняется, а затем значение увеличивается или уменьшается. Пожалуйста, обратитесь к официальной документации о операторах в java
class PrePostDemo {
public static void main(String[] args){
int i = 3;
i++;
// prints 4
System.out.println(i);
++i;
// prints 5
System.out.println(i);
// prints 6
System.out.println(++i);
// prints 6
System.out.println(i++);
// prints 7
System.out.println(i);
}
}
Ответ 3
постдекремента
Post-Decrement принимает форму variable-name. Это говорит компилятору, чтобы сначала использовать исходное значение, а afterawrds уменьшает его, поэтому, если у нас есть что-то вроде этого:
for (int i = 10; i > 0; i--)
{
System.out.println(i);
}
Выход будет следующим:
1: 10
2: 9
3: 8
4: 7
5: 6
6: 5
7: 4
8: 3
9: 2
10: 1
предекремент
Pre-Decrement принимает оператор формы имя-переменной и используется, когда вы хотите уменьшить его, прежде чем использовать значение. Тот же самый код будет заканчиваться на 0 вместо 1. Это происходит потому, что функция уменьшила значение до того, как оно использовало значение.
Как это относится к рекурсивным вызовам?
Каждый рекурсивный вызов - это собственный стек, поэтому, когда вы передаете num-- в рекурсивную функцию, вы буквально передаете исходное значение num, а когда дочерний вызов завершается (в этом случае никогда), родительский вызов будет затем уменьшает число. Поскольку у вас нет другого базового случая, который правильно завершает вызов, это приводит к бесконечной рекурсии.
Ответ 4
Фактически это происходит из-за оператора пост декремента в методе.
public static void countForwards( int num ) {
if (num >= 0){
countForwards(num--);
}
System.out.print(num + " ");
}
Теперь, когда функция снова вызывает countForwards, она всегда принимает значение num как 5 из-за пост-декремента в методе, пожалуйста, попробуйте изменить как пре-декремент
public static void countForwards( int num ) {
if (num >= 0){
countForwards(--num);
}
System.out.print(num + " ");
}
Это будет работа, потому что значение сначала уменьшается, а затем это значение использует метод.
поскольку функция снова вызывает вызов, и они являются примитивными и хранятся в стеке. Вот почему он показывает переполнение стека.
public static void countForwards( int num ) {
if (num >= 0){
countForwards(num - 1);
}
System.out.print(num + " ");
}
Это работает, потому что это выражение, которое пытается сначала решить, а затем функция может использовать значение этого выражения. Надеюсь, он ответит на ваш вопрос.