Подтвердить что ты не робот

Что приводит к сбою этой рекурсивной функции по сравнению с другой почти идентичной?

Это приводит к ошибке. Мне просто нужна помощь, объясняющая, почему это происходит с ошибкой по сравнению с правильным. Я использовал отладчик, но мне все еще не ясно.

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 + " ");
}
4b9b3361

Ответ 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 + " ");

}

Это работает, потому что это выражение, которое пытается сначала решить, а затем функция может использовать значение этого выражения. Надеюсь, он ответит на ваш вопрос.