题目:力扣148 .排序链表
链接:https://leetcode.cn/problems/sort-list/description/
今天废了好大的劲才弄明白链表归并排序的细节,特记录下来,以方便大家参考和我后续复习查看!
方法:基于迭代思想的归并排序。
思路: ① 定义一个虚拟头结点dum, pre=dum,cur=head,dum->next=head;统计链表的长度length。
② 定义一个sublength,控制每次移动cur的次数,初始值为1。每次循环,sublength<<=1;
③ 链表切分的细节:
1)head1=cur,从链表的第一个元素出发,按照sublength(同时判断cur->next!=nullptr)寻找第一个链表的结尾。保存cur->next的下一个元素,并切断cur与之后链表元素的联系,以防产生自环。
2)让cur移动到第二个链表的第一个元素,head2=cur;按照sublength(同时判断cur->next!=nullptr和cur!=nullptr)寻找第二个链表的结尾。保存cur->next的下一个元素,并切断cur与之后链表元素的联系,以防产生自环。
3)将head1和head2送入归并排序函数进行排序,返回合并后链表的头指针tmp,并让pre->next=tmp; pre移动到tmp的末尾,为下一次的循环做准备。重复1) 、2) 、 3)。
初始状态各个指针的位置:
将3和2分开之后:接下来对head1和head2排序:
然后cur=next,进行接下来的分割,合并,拼接到pre的后面。
完整代码:
class Solution {
public:`
ListNode* sortList(ListNode* head) {
int length=0,sublength=1;
ListNode *tmp=head;
ListNode *tmp1;
ListNode*tmp2;//返回两个子链表排序后,新链表的头指针
while (tmp!=nullptr)
{
length++;
tmp=tmp->next;
}
ListNode*dum=new ListNode(0,head);//定义一个虚拟头结点
for(sublength=1;sublength<length;sublength<<=1)
{
ListNode*pre=dum,*cur=dum->next;//每次初始化pre和cur
ListNode*head1,*head2;
while (cur!= nullptr)
{
head1=cur;//第一个链表的首结点
for(int i=1;i<sublength && cur->next!=nullptr;i++)
{
cur=cur->next;
}
head2=cur->next;
cur->next=NULL;
cur=head2;
for(int i=1;i<sublength && cur!=nullptr && cur->next!=nullptr;i++) //去掉cur!=nullptr在这里报错
{
cur=cur->next;
}
ListNode* next=nullptr;//next每次要初始化为空指针
if(cur!=nullptr)
{
next=cur->next;
cur->next=nullptr;
}
tmp2=merge(head1, head2);
//将tmp2接入到已排序链表的后面
//移动pre指针,pre的移动步数与sublength有关,为其2倍;
pre->next=tmp2;
while (pre->next!=nullptr) //添加尾部出错pre->next->next存在,但是pre->next->next->next=NULL。正常应该是直接对
{
pre=pre->next;
}
cur=next; //下一组要合并链表的头指针
}
}
return dum->next;
}
ListNode* merge(ListNode* head1, ListNode* head2) {
ListNode* dummyHead = new ListNode(0);
ListNode* temp = dummyHead, *temp1 = head1, *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;
}
};
暴力思想
先遍历一遍链表,然后存储链表值到向量中(太low啦)
//暴力排序
class Solution {
public:`
vector<int> arry;
ListNode* tmp=head;
while (tmp)
{
arry.push_back(tmp->val);
tmp=tmp->next;
}
sort(arry.begin(),arry.end());
tmp=head;
int i=0;
while (tmp)
{
tmp->val=arry[i];
i++;
tmp=tmp->next;
}
return head;
};