Как работает рекурсия в JAVA?

Есть небольшой код

public class Driver {
    public static void main(String[] args) {
        System.out.println(drive(4, 6));
    }
    public static int drive(int a, int b) {

        if (a == 0) return Math.abs(a - b);

        return Math.min(
                        drive(a - 1, b + 1),
                        drive(a - 1, b + 1)
        );
    }
}

Вопрос: почему когда "a" становится 0, не происходит выход из метода, а наоборот "a" становится 1, потом 2, потом снова 1 и так ещё несколько итераций.

Целый вечер сижу никак не могу разобраться как это работает. В дебаг режиме запускал код, и всё равно не понял откуда берутся значения "a" после того, как она опускается к 0.

Спасибо!


Ответы (2 шт):

Автор решения: Aziz Umarov

Eсли немного поменять код то можно увидеть сколько раз будет вызывается рекурсия

public class Driver {
    public static void main(String[] args) {
        System.out.println(drive(4, 6));
    }
    public static int drive(int a, int b) {
        System.out.printf("\n(a = %d b = %d)", a, b);
        if (a == 0) return Math.abs(a - b);

        return Math.min(
                        drive(a - 1, b + 1),
                        drive(a - 1, b + 1)
        );
    }
}

вывод такой

(a = 4 b = 6)
(a = 3 b = 7)
(a = 2 b = 8)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 2 b = 8)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 3 b = 7)
(a = 2 b = 8)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 2 b = 8)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)
(a = 1 b = 9)
(a = 0 b = 10)
(a = 0 b = 10)10
→ Ссылка
Автор решения: Stanislav Volodarskiy

Вас путает то что в функции drive два рекурсивных вызова. Я нарисую дерево вызовов, а вы проверите в отладчике, что значения a и b меняются именно в таком порядке:

drive(4, 6)
    drive(3, 7)
        drive(2, 8)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
        drive(2, 8)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
    drive(3, 7)
        drive(2, 8)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
        drive(2, 8)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)
            drive(1, 9)
                drive(0, 10)
                drive(0, 10)

Если вы в отладчике поставить точку останова в начале функции, то получите такую последовательность значений a:

4 3 2 1 0 0 1 0 0 2 1 0 0 1 0 0 3 2 1 0 0 1 0 0 2 1 0 0 1 0 0

Посмотрите стек вызовов. В нём значения a будут выглядеть так:

4
4 3
4 3 2
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3
4 3 2
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
4 3 2 1 
4 3 2 1 0 
4 3 2 1 0 
→ Ссылка