为什么将middle.next设置为null?

时间:2019-04-23 05:45:19

标签: java linked-list mergesort

因此,我正在尝试对该链接列表进行排序,我理解代码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 result; 
    } 

    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 

5 个答案:

答案 0 :(得分:0)

因此,如果您看到完整的代码,将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, &a, &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);

它有效地将列表分为两半,并通过调用相同的方法将它们单独合并。为了达到相同的目的,首先要复制nextofmiddle中的下一个值,然后使它们middle.next = null;中断递归循环。

我希望这可以澄清您的疑问。

答案 1 :(得分:0)

因此,看来作者正在方法node getMiddle(node h)中寻找列表的中间点。这将返回中间节点,但是您要将列表分为两部分,左侧和右侧。

设置middle.next = null会将列表分为两部分。

答案 2 :(得分:0)

将列表分成两部分:找到中间元素时,第一部分将在中间元素结尾,因此middle.next设置为null。 middle.next的先前值是第二部分的开始。

答案 3 :(得分:0)

mergeSort将中间节点的next成员设置为null,以将列表h分为2个单独的列表hnextofmiddle它通过递归调用自身进行排序,然后合并以生成sortedList

但是请注意,此代码有一个主要问题:方法sortedMerge也是递归的,其堆栈深度为两个列表的组合长度,可能很大。编译器无法轻松地将这种递归简化为尾递归,因此使用此代码对长列表进行排序很可能会崩溃。

答案 4 :(得分:0)

middle.next = null的目的是将列表分为两部分。链表中最后一个节点之后的值应始终为NULL,这就是为什么作者将next节点的middle节点设置为NULL的原因。作者正在创建一个包含从headmiddle的节点的子列表,以及另一个包含从nextofmiddle到列表末尾的节点的子列表。每次调用此函数时,子列表都会分解为较小的部分,这是合并排序过程的一部分。