题目
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
法一:归并排序自顶向下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
//递归边界
if(head==nullptr || head->next==nullptr) return head;
ListNode *slow=head, *fast=head;
//双指针找到链表的中间节点,将链表一分为二
while(fast->next!=nullptr && fast->next->next!=nullptr)
{
fast=fast->next->next;
slow=slow->next;
}
fast=slow->next;
slow->next=nullptr;
slow=head;
//分别排序两个子链表,然后合并有序链表
ListNode *l1=sortList(slow);
ListNode *l2=sortList(fast);
return mergeTwoList(l1,l2);
}
//合并两个有序链表
ListNode* mergeTwoList(ListNode *l1, ListNode *l2)
{
if(l1==nullptr) return l2;
if(l2==nullptr) return l1;
ListNode dummy(-1);
ListNode *p=&dummy;
for(; l1!=nullptr && l2!=nullptr;p=p->next)
{
if(l1->val<l2->val)
{
p->next=l1;
l1=l1->next;
}else
{
p->next=l2;
l2=l2->next;
}
}
if(l1!=nullptr) p->next=l1;
else p->next=l2;
return dummy.next;
}
};
- 时间复杂度O(nlgn)
- 空间复杂度O(lgn),递归栈的空间开销
法二:归并排序自底向上
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
int length=0;//计算链表的长度
ListNode *p=head;
while(p!=nullptr)
{
length++;
p=p->next;
}
//头节点
ListNode dummy(-1,head);
//依次自底向上合并
for(int curLength=1; curLength<length; curLength*=2)
{
//pre始终指向当前有序链表的最后一个元素,cur指向当前还未排序的链表的第一个元素
ListNode *pre=&dummy, *cur=pre->next;
while(cur!=nullptr)
{
//记录待合并链表的第一个头节点
ListNode *head1=cur;
for(int i=1; i<curLength&&cur->next!=nullptr; i++)
cur=cur->next;
//记录待合并链表的第二个头结点
ListNode *head2=cur->next;
cur->next=nullptr;
cur=head2;
for(int i=1; i<curLength&&cur!=nullptr&&cur->next!=nullptr; i++)
cur=cur->next;
//next指向未排序链表的第一个节点
ListNode *next=nullptr;
if(cur!=nullptr)
{
next=cur->next;
cur->next=nullptr;//断开待合并链表与未排序链表
}
pre->next=mergeTwoList(head1, head2);//pre始终指向已排序链表的最后一个节点
while(pre->next!=nullptr)
pre=pre->next;
cur=next;//cur指向未排序链表的第一个元素
}
}
return dummy.next;
}
//合并两个有序链表
ListNode* mergeTwoList(ListNode *l1, ListNode *l2)
{
if(l1==nullptr) return l2;
if(l2==nullptr) return l1;
ListNode dummy(-1);
ListNode *p=&dummy;
for(; l1!=nullptr&&l2!=nullptr; p=p->next)
{
if(l1->val < l2->val)
{
p->next=l1;
l1=l1->next;
}else
{
p->next=l2;
l2=l2->next;
}
}
if(l1==nullptr) p->next=l2;
else p->next=l1;
return dummy.next;
}
};
- 时间复杂度O(nlgn)
- 空间复杂度O(1)
- 排序中的链表可以划分为四部分
- head到pre:已经排序好的链表
- head1到head2:待合并的链表1
- head2到cur:待合并的链表2
- cur以后:待划分然后合并的链表