Med Sort a linked list in O(n log n) time using constant space complexity.
对链表排序要求O(1)空间。排序可用merge sort,heap sort或quick sort。quick sort由于需要swap在这里并不好用,heap需要O(N)额外空间,只有merge sort符合条件(如果不考虑调用栈的空间消耗)。merge sort用到了分治的思想,和处理二叉树类似,把input space分成左右两部分,递归调用自己。假设已经左右已经排好序了,再把left和right list合并。把递归树画出来,会是一棵高度为lgn的二叉树,每层一共有n个结点,从一个层往上一层回溯一共耗时n排序(这里还有耗时n找中间结点),因此一共复杂度O(nlgn)。merge sort是稳定的。
/*
* @lc app=leetcode id=148 lang=cpp
*
* [148] Sort List
*/
// @lc code=start
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head == nullptr || head->next == nullptr) return head;
const auto mid = [&]() {
auto slow = head, fast = head->next;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
};
auto slow = mid(), next = slow->next;
auto r = sortList(slow->next);
slow->next = nullptr;
auto l = sortList(head);
ListNode *dummy = new ListNode(-1), *cur = dummy;
while (l != nullptr || r != nullptr) {
if (r == nullptr || l != nullptr && l->val <= r->val) {
cur->next = l;
l = l->next;
} else if (l == nullptr || r != nullptr && r->val <= l->val) {
cur->next = r;
r = r->next;
}
cur = cur->next;
}
return dummy->next;
}
};
// @lc code=end
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode mid = getMid(head);
ListNode right = sortList(mid.next);
mid.next = null;
ListNode left = sortList(head);
return merge(left, right);
}
private ListNode getMid(ListNode head) {
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode merge(ListNode left, ListNode right) {
ListNode dummy = new ListNode(0), node = dummy;
while (left != null && right != null) {
if (left.val < right.val) {
node.next = left;
left = left.next;
} else {
node.next = right;
right = right.next;
}
node = node.next;
}
if (left != null) {
node.next = left;
} else {
node.next = right;
}
return dummy.next;
}
}