148.排序链表
1.题目描述
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序
2.解题报告
针对nlogn的排序算法,主要有快速排序,归并排序和堆排序。其中,堆排序利用了数组的连续特性。所以这里不能采用。其次,在快速排序中,设计大量数字的交换且单链表因为只能单向遍历,使用partition不是很直观。
所以,本题采用归并排序链表版来实现。
具体思路如下:
1.使用快慢指针,找到链表的中点。
2.对链表的前半部分和后半部分分别排序。
3.将两部分合并。
代码
/**
* 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) {
return sortList(head, NULL);
}
private:
// sort [beg, end), and return new head, and tail->next = end;
ListNode* sortList(ListNode*beg, ListNode* end) {
if (beg == end || !beg || beg->next == end) {
return beg;
}
// at least has two node
// [head, mid, end], maybe head == mid == end
// [head, mid) < mid < [mid->next, end)
ListNode* head = NULL; // new head
ListNode* mid = NULL;
beg = partition(beg, end, &head, &mid);
// sort [mid->next, end)
if (mid && mid->next != end) {
mid->next = sortList(mid->next, end);
}
// sort [head, mid)
return sortList(head, mid);
}
ListNode* partition(ListNode* beg, ListNode* end,
ListNode** p_head, ListNode** p_mid) {
if (!beg || !p_head || !p_mid) {
return beg;
}
ListNode* mid = beg;
ListNode* tail1 = NULL;
ListNode* tail2 = NULL;
int v = mid->val;
ListNode* p = mid->next;
while (p != end) {
if (p->val < v) {
if (!*p_head) {
*p_head = p;
tail1 = p;
} else {
tail1->next = p;
tail1 = p;
}
} else {
if (!tail2) {
mid->next = p;
tail2 = p;
} else {
tail2->next = p;
tail2 = p;
}