Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

(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;
}  
like image 996
Alonzo Robbe Avatar asked Apr 22 '17 15:04

Alonzo Robbe


People also ask

What is the space complexity of merge sorting a linked list?

The Space Complexity of Merge Sort is O(log N) where N is the number of nodes in the linked list. This is because Merge sort algorithm is recursive, it requires O(log N) stack space for linked list cases.

Can merge sort be done in O 1 space?

Yes, it's possible to perform an in-place merge sort. That does not mean it doesn't require any extra memory, since the recursion still takes O(lg n) stack space (just like quicksort).

What is the time complexity of merge sort nLogn?

The list of size N is divided into a max of Logn parts, and the merging of all sublists into a single list takes O(N) time, the worst-case run time of this algorithm is O(nLogn) Best Case Time Complexity: O(n*log n) Worst Case Time Complexity: O(n*log n) Average Time Complexity: O(n*log n) The time complexity of ...

Why merge sort complexity is O nLogn?

MergeSort algorithm takes three steps: Divide step computes mid position of sub-array and it takes constant time O(1). Conquer step recursively sort two sub arrays of approx n/2 elements each. Combine step merges a total of n elements at each pass requiring at most n comparisons so it take O(n).


1 Answers

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.
like image 163
ruakh Avatar answered Oct 04 '22 13:10

ruakh