经典链表排序题
- 链表排序最佳方案:归并排序
- 切分子链表时用快慢指针法找中点(注意fast初始位置非head)
- 递归终点为只剩一个节点(即!head->next),此时自然有序
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head) {
/*
1.链表排序的最佳选择:归并
2.先归后并,归用递归,依次将链表切割为小链表
3.归完要并,过程等价于合并两个有序链表
*/
// 设计递归函数,经过该递归函数后链表变为有序
return recursion(head);
}
ListNode* recursion(ListNode* head){
// 确定递归终点
if(!head->next) // 只剩1个节点的时候递归结束,自然有序
return head;
// 找中点,每次递归划分成两个子链表
// 用双指针总结帖中“快慢指针找中点”法
ListNode* slow = head;
ListNode* fast = head->next;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
// 此时slow指针位于链表中点,分割子链表
ListNode* mid = slow;
ListNode* newHead = mid->next;
mid->next = nullptr;
// 归完要并
return merge(sortInList(head),sortInList(newHead));
}
ListNode* merge(ListNode* p1, ListNode* p2){
// 该函数用于合并两个有序链表
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
while(p1 && p2){
if(p1->val <= p2->val){
cur->next = p1;
cur = cur->next;
p1 = p1->next;
}
else{
cur->next = p2;
cur = cur->next;
p2 = p2->next;
}
}
// 如果原链表节点个数为偶数,到上面就已经合并完了,如果是奇数,两个子链表p1和p2长度不同,需要将剩下的部分接上
if(p1)
cur->next = p1;
if(p2)
cur->next = p2;
return dummy->next;
}
};