<LeetCode C++> 排序链表
给你链表的头结点head ,请将其按升序排列并返回排序后的链表。你可以在O(nlogn)时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
在对数组的排序算法中常见的O(nlogn)的排序算法有: 快速排序、归并排序和堆排序。但是快速排序和堆排序都需要对特定下标进行位置运算,不适用于链表排序的情况,所以这道题目使用归并排序。
举个简单的例子,对于[5, 4, 6, 3, 2, 8, 7, 1]
- size = 1: (4 -> 5) -> (3 -> 6) -> (2 -> 8) ->(1 -> 7)
- size = 2: (3 -> 4 -> 5 -> 6) -> (1 -> 2 -> 7 -> 8)
- size = 4: (1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8)
关于合并链表,可以先做21. 合并两个有序链表这道题。
实现代码如下:
class Solution {
public:
ListNode* merge(ListNode* l1, ListNode* l2) {
if(!l1) return l2;
if(!l2) return l1;
ListNode* l0 = new ListNode(0);
ListNode* ans = l0;
while(l1 && l2){
if(l1 -> val < l2 -> val){
l0 -> next = l1;
l1 = l1 -> next;
}
else{
l0 -> next = l2;
l2 = l2 -> next;
}
l0 = l0 -> next;
}
if(l1)
l0 -> next = l1;
else
l0 -> next = l2;
return ans -> next;
}
ListNode* cut(ListNode* head, int n){
auto p = head;
while(--n && p){
p = p -> next;
}
if(!p) return NULL;
auto next = p -> next;
p -> next = NULL;
return next;
}//返回一个以head为头,大小为n的链表
ListNode* sortList(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
auto p = head;
int length = 0;
while(p && ++length)
p = p -> next;
for(int size = 1; size < length; size <<= 1){
auto cur = dummyHead->next;
auto tail = dummyHead;
while(cur){
auto left = cur;
auto right = cut(left, size);
cur = cut(right, size);
tail->next = merge(left, right);
while(tail->next){
tail = tail -> next;
}//tail用来连接切割后的链表
}
}
return dummyHead->next;
}
};