力扣148:排序链表
题目描述
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
输入输出样例
输入:head = [4,2,1,3]
输出:[1,2,3,4]
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
输入:head = []
输出:[]
解法一,使用递归的归并排序,自顶向下,空间复杂度为O(logN)
class Solution
{
public:
ListNode *sortList(ListNode *head)
{
return sortListNode(head,nullptr);
}
ListNode *sortListNode(ListNode *head,ListNode *tail)
{
if(head==nullptr)
{
return head;
}
if(head->next==tail)
{
head->next=nullptr;
return head;
}
ListNode*slow=head;
ListNode*fast=head;
//寻找链表的中点
while(fast!=tail)
{
slow=slow->next;
fast=fast->next;
if(fast!=tail)
{
fast=fast->next;
}
}
ListNode *mid=slow;
//一直递归实现归并
return merge(sortListNode(head,mid),sortListNode(mid,tail));
}
ListNode *merge(ListNode*head1,ListNode*head2)
{
//建立哑结点
ListNode *dummyHead=new ListNode(0);
ListNode *temp=dummyHead;
ListNode *temp1=head1;
ListNode *temp2=head2;
while(temp1!=nullptr&&temp2!=nullptr)
{
if(temp1->val<=temp2->val)
{
temp->next=temp1;
temp1=temp1->next;
}
else{
temp->next=temp2;
temp2=temp2->next;
}
temp=temp->next;
}
if(temp1!=nullptr)
{
temp->next=temp1;
}
else if(temp2!=nullptr)
{
temp->next=temp2;
}
return dummyHead->next;
}
};
解法二,使用非递归的归并排序,自顶向下算法,空间复杂度O(1)
//使用自底向上的归并排序
//非递归的方式
//首先需要获取链表的长度
//sublength 表示每次需要排序的子链表的长度
//将列表拆分成若干长度为subLength的子链表,按照每两个子链表一组进行合并,得到若干字串,然后再继续按照算法进行合并
class Solution2
{
public:
ListNode *sortList(ListNode *head)
{
if(head==nullptr)
{
return head;
}
int length=0;
ListNode *node=head;
//获得链表的长度
while(node!=nullptr)
{
length++;
node=node->next;
}
//创建哑结点
ListNode *dummyHead=new ListNode(0,head);
//sublength<<=1 相当于subLength=sublength*2
for(int subLength=1;subLength<length;subLength<<=1)
{
//首先设置结点指向
//prev指向哑结点
//curr指向给定的链表
ListNode *prev=dummyHead;
ListNode *curr=dummyHead->next;
while(curr!=nullptr)
{//head1指向的是当前要连接的第一个结点
ListNode *head1=curr;
for(int i=1;i<subLength&&curr->next!=nullptr;i++)
{
curr=curr->next;
}
//head2指向当前要连接的第二个子节点
ListNode *head2=curr->next;
//这边将curr->next=nullptr 是使得 header1 后面不再连接别的结点
curr->next=nullptr;
//使curr重新指向head2结点,可跳过head1
curr=head2;
for(int i=1;i<subLength&&curr!=nullptr&&curr->next!=nullptr;i++)
{
curr=curr->next;
}
ListNode *next=nullptr;
if(curr!=nullptr)
{
//这里也是让 next保存head2之后的结点,并将head2之后的结点设置为nullptr
next=curr->next;
curr->next=nullptr;
}
//合并两个列表,并用prev指向
ListNode *merged=merge(head1,head2);
prev->next=merged;
//使prev指向链表的末尾
while(prev->next!=nullptr)
{
prev=prev->next;
}
//这里再进行接下来的两两共同处理
curr=next;
}
}
return dummyHead->next;
}
ListNode *merge(ListNode*head1,ListNode*head2)
{
//建立哑结点
ListNode *dummyHead=new ListNode(0);
ListNode *temp=dummyHead;
ListNode *temp1=head1;
ListNode *temp2=head2;
while(temp1!=nullptr&&temp2!=nullptr)
{
if(temp1->val<=temp2->val)
{
temp->next=temp1;
temp1=temp1->next;
}
else{
temp->next=temp2;
temp2=temp2->next;
}
temp=temp->next;
}
if(temp1!=nullptr)
{
temp->next=temp1;
}
else if(temp2!=nullptr)
{
temp->next=temp2;
}
return dummyHead->next;
}
};