单链表的排序
题目链接:单链表的排序
解题思路1:分治、双指针
分治就是分而治之的意思,分的意思是说将一个大且复杂的问题划分成多个性质相似但是规模更小的问题,子问题继续按照同样的思路进行划分,直到问题被划分为可以轻易解决的问题;治的意思是说将子问题单独进行处理。经过分治后的子问题,需要将各个子问题的解进行合并才能得到原问题的解,因此整个分治过程经常采用递归来实现
找到链表中间元素的前一个节点,将其断开,就可以将链表划分成两个子链表,然后继续划分,直到最小,为空或为单独一个节点,然后依次往上合并
终止条件:当子链表划分到为空或者只剩一个节点时,不再继续划分,往上合并
返回值:每次返回两个排好序且合并好的子链表
本级任务:找到链表的中间节点,从前面断开,分为左右两个子链表,进入子问题的排序
我们通过双指针来找到中间元素,快指针每次走两步,慢指针每次走一步,这样当快指针到达链表尾的时候,慢指针刚好走了快指针的一半
具体步骤:
首先判断链表为空或者只有一个元素,直接就是有序的
准备三个指针,快指针right每次走两步,慢指针mid每次走一步,前序指针left每次跟在mid前一个位置。三个指针遍历链表,当快指针到达链表尾部的时候,慢指针mid刚好走了链表的一半,正好是中间位置
从left位置将链表断开,刚好分成两个子问题开始递归
将子问题得到的链表合并
代码如下:
//合并两个链表
ListNode* merge(ListNode* head1, ListNode* head2){
if(head1 == nullptr) return head2;
if(head2 == nullptr) return head1;
ListNode* head = new ListNode(0);
ListNode* cur = head;
while(head1 != nullptr && head2 != nullptr){
if(head1->val <= head2->val){
cur->next = head1;
head1 = head1->next;
}else{
cur->next = head2;
head2 = head2->next;
}
cur = cur->next;
}
if(head1){
cur->next = head1;
}
if(head2){
cur->next = head2;
}
return head->next;
}
ListNode* sortInList(ListNode* head) {
if(head == nullptr || head->next == nullptr)
return head;
ListNode* left = head;
ListNode* mid = head->next;
ListNode* right = head->next->next;
while(right != nullptr && right->next != nullptr){
left = left->next;
mid = mid->next;
right = right->next->next;
}
left->next = nullptr;
return merge(sortInList(head), sortInList(mid));
}
解题思路2:借助数组
首先遍历链表,将节点值加入到数组中
对数组元素进行排序
依次遍历数组和链表,按照位置将链表中的节点值修改为排序后相应位置的数组值
代码如下:
ListNode* sortInList(ListNode* head) {
vector<int> v;
ListNode* p = head;
while(p != nullptr){
v.push_back(p->val);
p = p->next;
}
p = head;
sort(v.begin(), v.end());
for(auto const& e : v){
p->val = e;
p = p->next;
}
return head;
}