Почему для middle.next установлено значение null?

#java #linked-list #mergesort

#java #связанный список #сортировка слиянием

Вопрос:

Итак, я пытаюсь отсортировать этот связанный список, я понимаю каждую часть кода, кроме этого небольшого фрагмента, в функции mergeSort , строка 9. почему middle.next должно быть установлено значение null ? Я не понимаю, что это делает, что необходимо?

Вот ссылка на то, откуда я получил код (в примере кода Java):

https://www.geeksforgeeks.org/merge-sort-for-linked-list/

Вот код:

 // Java program to illustrate merge sorted 
// of linkedList 

public class linkedList { 
    node head = null; 
    // node a, b; 
    static class node { 
        int val; 
        node next; 

        public node(int val) { 
            this.val = val; 
        } 
    } 

    node sortedMerge(node a, node b) { 
        node result = null; 
        /* Base cases */
        if (a == null) 
            return b; 
        if (b == null) 
            return a; 

        /* Pick either a or b, and recur */
        if (a.val <= b.val) { 
            result = a; 
            result.next = sortedMerge(a.next, b); 
        } else { 
            result = b; 
            result.next = sortedMerge(a, b.next); 
        } 
        return resu< 
    } 

    node mergeSort(node h) { 
        // Base case : if head is null 
        if (h == null || h.next == null) { 
            return h; 
        } 

        // get the middle of the list 
        node middle = getMiddle(h); 
        node nextofmiddle = middle.next; 

        // set the next of middle node to null 
        middle.next = null; 

        // Apply mergeSort on left list 
        node left = mergeSort(h); 

        // Apply mergeSort on right list 
        node right = mergeSort(nextofmiddle); 

        // Merge the left and right lists 
        node sortedlist = sortedMerge(left, right); 
        return sortedlist; 
    } 

    // Utility function to get the middle of the linked list 
    node getMiddle(node h) { 
        // Base case 
        if (h == null) 
            return h; 
        node fastptr = h.next; 
        node slowptr = h; 

        // Move fastptr by two and slow ptr by one 
        // Finally slowptr will point to middle node 
        while (fastptr != null) { 
            fastptr = fastptr.next; 
            if (fastptr != null) { 
                slowptr = slowptr.next; 
                fastptr = fastptr.next; 
            } 
        } 
        return slowptr; 
    } 

    void push(int new_data) { 
        /* allocate node */
        node new_node = new node(new_data); 

        /* link the old list off the new node */
        new_node.next = head; 

        /* move the head to point to the new node */
        head = new_node; 
    } 

    // Utility function to print the linked list 
    void printList(node headref) { 
        while (headref != null) { 
            System.out.print(headref.val   " "); 
            headref = headref.next; 
        } 
    } 

    public static void main(String[] args) { 

        linkedList li = new linkedList(); 
        /* 
         * Let us create a unsorted linked list to test the functions 
         * created. The list shall be a: 2->3->20->5->10->15 
         */
        li.push(15); 
        li.push(10); 
        li.push(5); 
        li.push(20); 
        li.push(3); 
        li.push(2); 

        // Apply merge Sort 
        li.head = li.mergeSort(li.head); 
        System.out.print("n Sorted Linked List is: n"); 
        li.printList(li.head); 
    } 
} 

// This code is contributed by Rishabh Mahrsee 
  

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

1. Похоже, что он разбивает список на два меньших списка, поэтому он может рекурсивно вызывать себя

2. Обратите внимание, что итеративная сортировка слиянием снизу вверх для связанного списка устраняет необходимость сканирования для разделения списков. Вместо этого он использует небольшой (от 26 до 32) массив указателей или ссылок на узлы.

3. @AlanKamali: вы можете принять один из ответов, нажав на серую галочку под его оценкой.

Ответ №1:

mergeSort задает next члену среднего узла значение null для разделения списка h на 2 отдельных списка, h и nextofmiddle которые он сортирует, вызывая себя рекурсивно, а затем объединяет для получения sortedList .

Однако обратите внимание, что у этого кода есть серьезная проблема: метод sortedMerge также рекурсивен с глубиной стека, равной суммарной длине обоих списков, что потенциально является большим числом. Эта рекурсия не может быть легко упрощена компилятором как хвостовая рекурсия, следовательно, сортировка длинных списков с помощью этого кода, скорее всего, приведет к сбою.

Ответ №2:

Цель middle.next = null состоит в том, чтобы разбить список на две части. Значение после последнего узла в связанном списке всегда должно быть NULL, поэтому автор установил для next узла middle node значение NULL. Автор создает один подсписок, содержащий узлы от head до middle , и второй подсписок, содержащий узлы от nextofmiddle до конца списка. Каждый раз, когда вызывается эта функция, подсписок разбивается на более мелкие части, что является частью процесса сортировки слиянием.

Ответ №3:

Итак, если вы видите весь код целиком, mergeSort() вызывается рекурсивно,

  // Apply mergeSort on left list 
    node left = mergeSort(h); 

 // Apply mergeSort on right list 
    node right = mergeSort(nextofmiddle); 
  

И, помещая middle.next = null , это фактически нарушает рекурсию вызывающего метода в стеке методов. Таким образом, он вернет текущий узел, когда мы рекурсивно вызовем тот же метод,

 if (h == null || h.next == null) { 
    return h; 
}
  

Итак, если вы видите код psedo,

 MergeSort(headRef)
1) If the head is NULL or there is only one element in the Linked List 
   then return.
2) Else divide the linked list into two halves.  
   FrontBackSplit(head, amp;a, amp;b); /* a and b are two halves */
3) Sort the two halves a and b.
    MergeSort(a);
    MergeSort(b);
4) Merge the sorted a and b (using SortedMerge() discussed here) 
   and update the head pointer using headRef.
   *headRef = SortedMerge(a, b);
  

Это эффективно разбивает список на 2 половины и сортирует их по отдельности, вызывая один и тот же метод. Для достижения того же самого сначала копируется следующее значение в nextofmiddle и они делают middle.next = null; , чтобы прервать цикл рекурсии.

Я надеюсь, что это прояснит ваши сомнения.

Ответ №4:

Итак, похоже, что автор ищет среднюю точку списка в методе node getMiddle(node h) . Это возвращает средний узел, но вы хотите разбить список на две части: левую и правую.

Настройка middle.next = null разбивает список на две части.

Ответ №5:

Это для разделения списка на две части: когда средний элемент найден, первая часть будет заканчиваться на среднем элементе, поэтому middle.next установлено значение null. Предыдущее значение middle.next является началом второй части.