本题目来源于LeetCode,具体如下:
Sort a linked list in O(n log n) time using constant space complexity.
题目要求复杂度O(nlogn),因此我们很自然考虑使用快速排序或者归并排序,但是后来经过实践证明,使用快速排序总是AC超时,归并排序则可以正确AC。
分析一下原因,个人认为是 与测试数据有关,因为快速排序不能保证算法复杂度一定是O(nlogn),当数据比较集中时,即使做随机选取key值,算法的复杂度也非常接近O(N^2),因此会出现超时,所以考虑使用归并排序。
下面是采用归并排序的思路已经AC代码:
主要考察 3 个知识点,
知识点 1 :归并排序的整体思想
知识点 2 :找到一个链表的中间节点的方法
知识点 3 :合并两个已排好序的链表为一个新的有序链表
归并排序的基本思想是:找到链表的 middle 节点,然后递归对前半部分和后半部分分别进行归并排序,最后对两个以排好序的链表进行 Merge 。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getMid(ListNode *head) {
if(NULL == head || NULL == head->next) return head;
ListNode *slowPointer = head;
ListNode *fastPointer = head->next;
while(fastPointer && fastPointer->next) {
slowPointer = slowPointer->next;
fastPointer = fastPointer->next->next;
}
return slowPointer;
}
ListNode *mergeList(ListNode *leftHead, ListNode *rightHead)
{
ListNode *newHead = new ListNode(-1);
ListNode *newTail = newHead;
while(leftHead != NULL && rightHead != NULL) {
if(leftHead->val > rightHead->val) {
newTail->next = rightHead;
rightHead=rightHead->next;
}
else {
newTail->next = leftHead;
leftHead=leftHead->next;
}
newTail = newTail->next;
}
if(leftHead != NULL) newTail->next = leftHead;
if(rightHead != NULL) newTail->next = rightHead;
ListNode *del = newHead;
newHead = newHead->next;
delete del;
return newHead;
}
ListNode *sortList(ListNode *head) {
if(NULL == head || NULL == head->next) return head;
ListNode *mid = getMid(head);
ListNode *leftHead = head;
ListNode *rightHead = mid->next;
mid->next = NULL;
leftHead = sortList(leftHead);
rightHead = sortList(rightHead);
return mergeList(leftHead, rightHead);
}
};