Рекурсия при слиянии связанных списков

Я начинаю понимать рекурсию,

Я прикрепил рекурсивный код для объединения двух отсортированных связанных списков,

Моя проблема в том, что я понимаю, что temp возвращает значение temp -> (first (or) second), как только первое или второе становится нулевым, но я не могу понять тот факт, что,

Скажем, например, если у меня 5 -> 10 -> 15 -> 20.

Последняя функция возвращает 15 -> 20, которые затем объединяются как root.next-> temp, но после этого шага, когда я возвращаю temp, почему возвращается корневое значение. т.е. 10 -> 15 -> 20, когда я ожидаю, что будет возвращена только температура.

Пожалуйста, найдите код,

 /**
 * 
 */
 *
 *
 */
public class MergeLinkedLists {

    static class Node {

        int data;
        Node next;

        public Node(int value) {
            this.data = value;
        }

    }

    Node root;

        /**
     * @param args
     */

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MergeLinkedLists s1 = new MergeLinkedLists();
        s1.root = new Node(0);
        Node n1 = new Node(10);
        //n1.next = new Node(20);
        //n1.next.next = new Node(30);

        Node n2 = new Node(5);
        n2.next = new Node(15);
        //n2.next.next = new Node(50);

        Node result = sortedLists(n1, n2, s1.root);

        while (result != null) {
            System.out.print(result.data + "--->");
            result = result.next;
        }
    }

    /**
     * @param n1
     * @param n2
      * @param root2
     */
     private static Node sortedLists(Node n1, Node n2, Node root) {
         // TODO Auto-generated method stub

        Node temp = root;

        Node first = n1; // 10 20 30
        Node second = n2; // 5 15 50

        if (first == null) {
            temp.next = second;
            return temp;
        } else if (second == null) {
            temp.next = first;
            return temp;
        }

        else if (first.data < second.data) {
            temp = new Node(first.data);
            first = first.next;
        } else {
            temp = new Node(second.data);
            second = second.next;
        }

        sortedLists(first, second, temp);
        root.next = temp;
        System.out.println("The Temp Data is ::::"+temp.data);
        return temp;

    }

}

Добро пожаловать в SO! Эта функция написана довольно запутанно, но, насколько я могу судить, работает отлично. Можете прояснить, в чем ваша проблема? Ваши возвращаемые значения здесь не имеют значения, за исключением первого вызова функции, который возвращает правильный результат (следующее значение фиктивного корня, то есть root.next) в основную область видимости.

ggorlen 24.11.2018 08:17
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Потому что tempявляется в данном случае корневое значение. Не волнуйтесь, это единственное, что вам нужно понять, чтобы понять саму рекурсию.

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

Помимо этого, давайте посмотрим на ваш код.

Важно отметить, что всякий раз, когда вы вызываете свой sortedLists(first, second, temp);, указатель будет попадать в него, пока функция не завершится (то есть, когда он вернет temp). Вы вызовете эту функцию несколько раз по мере продолжения работы программы, чтобы она глубже погрузилась в свою собственную функцию. Затем он передает информацию шаг за шагом на уровне до тех пор, пока первый вызов sortedLists(first, second, temp); не завершится, и это будет в вашем основном методе Node result = sortedLists(n1, n2, s1.root);.

Я постараюсь обойтись вашим примером:

  1. Node result = sortedLists(n1, n2, s1.root); вызывается в методе main(). Итак, корень равен 0, и у вас есть узлы 10 и 5,15.

  2. При первом вызове sortedLists() temp становится 5, а second теперь несет 15, потому что first.data > second.data.

  3. В НАСТОЯЩЕЕ ВРЕМЯ Вы снова вызываете метод sortedLists(), но с новыми значениями: теперь корень равен 5, первое остается 10, а второе - 15. Мы выполняем шаг внутри функции и начинаем с новых значений:

    1. из-за first.data < second.data значение temp становится равным 10, теперь значение first равно нулю.
    2. и снова: мы получили еще один звонок на sortedLists(). Мы передаем значения: first = null second = 15 root = 10 функции и идем на один шаг глубже.
      1. поскольку first теперь равен нулю, temp.next будет second (15)
      2. temp теперь выглядит так: 10-> 15 и мы возвращаемся. (это первый раз, когда sortedLists() отключается!)
    3. Теперь мы вернулись сюда и можем продолжить работу с root.next = temp;. Помните, какая временная температура была в этом контексте? темп был 10, но он был обновлен функцией выше. Новый temp - это 10-> 15, поэтому наш root выглядит так: 5-> 10-> 15.
    4. Затем вы печатаете заголовок temp, равный 10. Эта функция также завершается.
  4. теперь мы вернулись к нашему первому вызову и посмотрим, что произойдет: в 3.3 мы обновили его корень. Корнем 3.3 был temp из 3, потому что мы вызвали sortedLists(first, second, temp) (temp действует как корень, потому что последний аргумент этой функции - Node root).

  5. Подводя итог: наш корень по-прежнему равен 0, а наша темп - 5-> 10-> 15.

  6. root.next находится после этого присвоения 0-> 5-> 10-> 15. Теперь корень, который вы объявили в своем классе над основным методом, имеет значение.

  7. мы возвращаем темп, равный 5-> 10-> 15, и все готово.

Теперь мы можем перейти к основному методу и распечатать результаты.

Чтобы избавиться от ---> при отсутствии result.next, вы можете обработать нулевое значение следующим образом:

 while (result != null) {
            if (result.next != null)
            System.out.print(result.data + "--->");
            else System.out.println(result.data);
            result = result.next;
        }

Надеюсь, это поможет немного разобраться в рекурсии.

Привет, e.Fro! Большое спасибо за ваше предложение, у меня есть небольшое сомнение в шаге 4, где вы говорите, что корень 3.3 равен temp из 3 ... Я понимаю ... но когда вызов функции 3.3 завершается, почему возвращается корневое значение .... где я возвращаю только temp. (10-> 15) .... все значения возвращаются в предыдущую вызывающую функцию .... Заранее спасибо.

stevens 24.11.2018 15:34

Я предполагаю, что вся концепция основана на передаче по значению, поскольку корневое значение вызываемой функции обновляется, оно отражается обратно в временном значении вызывающей функции. Пожалуйста, поправьте меня, если я ошибаюсь!

stevens 24.11.2018 16:57

Об объектах в Java следует помнить, что они уникальны, если вы их не воссоздаете (новый объект ()). Итак, ваша функция передает временный объект, а вызываемая функция назначает объект такой же корневым. Но сам объект остается прежним. Таким образом, если вы измените его, вы не просто измените его значение, ваша операция повлияет на весь объект. Это огромное преимущество, так как вы можете сэкономить много места. Таким образом, нет необходимости возвращать, поэтому вы не обрабатываете возвраты в рекурсии. Вы просто манипулируете самим объектом

e.Fro 24.11.2018 17:04

Этот подход называется на месте и также используется для быстрой сортировки. В контексте списков понравившихся это очень полезно использовать, потому что вы не хотите создавать новые элементы для манипуляций. Я надеюсь, что смогу вам немного помочь с этим. en.m.wikipedia.org/wiki/In-place_algorithm

e.Fro 24.11.2018 17:07

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

e.Fro 24.11.2018 17:12

Большое спасибо ! e.Fro

stevens 24.11.2018 17:22

Другие вопросы по теме