问题
(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 callsmergePass(..., 4)
on that result, etc., doublingi
each time. - stops before
i
is the length of the list (or bigger), sincemergePass(..., i)
is a no-op ifi
is that big. - returns the last result.
- calls
来源:https://stackoverflow.com/questions/43560711/how-to-merge-sort-a-linked-list-with-onlogn-time-and-o1-space-complexity