How to Merge sort a Linked List with O(nlogn) time and O(1) space complexity

旧城冷巷雨未停 提交于 2019-12-07 06:59:02

问题


(disclaimer: for school)

As far as I know, recursively splitting a linked list, then sending it off to another function to merge is O(nlogn) time and O(n) space. Is it possible to do mergesort on linked list with O(nlogn) time and O(1) space complexity? How would you go about doing this?

ANY HELP APPRECIATED

PS: to make sure that the traditional mergesort is space complexity 0(n), this is an example of 0(n), right? How would it be changed for O(1) space?

void sortTrack() { 
    Node merge = this.head;
    this.head = Node (merge);
}

public Node mergeSort(Node head){
    if ((head == null)||(head.next == null)){
        return head;
    }
    Node left = head;
    Node right = head.next;
    while((right != null) && right.next != null){
        head = head.next;
        right = right.next.next;
    }
    right = head.next;
    head.next = null;
    return merge(mergeSort(left), mergeSort(right));
}

public Node merge(Node left, Node right){
    Node head = new Node ();
    Node temp = head;
    while((left != null) && (right !=null)){
        if(left <= right ){
            temp.next = left;
            temp = left;
            left = left.next;
        }
        else{
            temp.next = right;
            temp = right; 
            right = right.next;
        }
    }
    if(right == null)
        temp.next = left;
    else
        temp.next = right;
    return head.next;
}  

回答1:


Your recursive approach requires Θ(log n) extra space, since you'll have Θ(log n) calls on the stack when you're all the way down to merge-sorting a singleton-list.

To reduce it to O(1) extra space, you'll need to change from a recursive "top-down" approach, where you split the list into two large sublists, sort them, and merge the results — giving you a recursive depth of Θ(log n) — to an iterative "bottom-up" approach where you first sort all the singleton-lists, then all the pairs (the first and second elements, then the third and fourth, etc.), then all the quartets (the first through fourth elements, then the fifth through eighth, etc.) — giving you Θ(log n) passes through the list. Each pass takes Θ(n) time, so the total time is still Θ(n log n).

So overall, you'll have three methods:

  • Node merge(Node listA, Node listB), which you've already written.

  • Node mergePass(Node list, int i):

    • precondition: nodes #1 to #n are sorted, nodes #(n+1) to #(2n) are sorted, etc.
    • postcondition: nodes #1 to #(2n) are sorted, nodes #(2n+1) to #(4n) are sorted, etc.
    • works by grabbing nodes #1 to #n and nodes #(n+1) to #(2n), "cutting" them out, calling merge, and "pasting" the result in; then doing the same for nodes #(2n+1) to #(3n) and nodes #(3n+1) to #(4n); etc.
  • Node mergeSort(Node list):

    • calls mergePass(..., 1) on its argument.
    • calls mergePass(..., 2) on the result, then calls mergePass(..., 4) on that result, etc., doubling i each time.
    • stops before i is the length of the list (or bigger), since mergePass(..., i) is a no-op if i is that big.
    • returns the last result.


来源:https://stackoverflow.com/questions/43560711/how-to-merge-sort-a-linked-list-with-onlogn-time-and-o1-space-complexity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!