链表排序应该最好写的是插入排序,但时间复杂度为O(N),今天遇到了链表的排序问题,记得曾经在leetcode上做了这道题,直接写插入排序会超时,后来只好采用归并排序(不仅时间复杂度为O(NlogN),空间复杂度还是O(1)),然后三下五除二地写了归并排序。以前写的非递归版本,大概是提交了5次调试N久之后通过的吧,今天在纸上一写,发现漏洞百出,后来才发现原来用递归的方式写可以省时省力!哎,当初费力AC了这道题之后应该看看讨论!
1. 链表的插入排序
ListNode *insertionSortList(ListNode *head) {
if(NULL == head || NULL == head->next)
return head;
ListNode *newHead = head;
ListNode *ptr = head->next;
newHead->next = NULL;
while(ptr)
{
ListNode *tmp = ptr;
ptr = ptr->next;
ListNode *q = newHead;
if(q->val >= tmp->val)
{
tmp->next = q;
newHead = tmp;
} else {
while(q && q->next && q->next->val < tmp->val)
{
q = q->next;
}
tmp->next = q->next;
q->next = tmp;
}
}
return newHead;
}
2. 链表的归并排序(传说中作死的非递归版本)
ListNode *sortList(ListNode *head) {
if(!head || !head->next) return head;
ListNode *ptr = head;
int n = 0;
while(ptr)
{
ptr = ptr->next;
++n;
}
for(int i = 1; i < n; i = i * 2)
{
ptr = head;
head = NULL;
ListNode *tail = NULL;
while(ptr)
{
ListNode *list1 = ptr;
ListNode *list2 = ptr;
int l1 = 0;
while(list2 && l1 < i) // locate list2
{
list2 = list2->next;
++l1;
}
ptr = list2;
int l2 = 0;
while(ptr && l2 < i) // locate ptr
{
ptr = ptr->next;
++l2;
}
int t = 0, s = 0;
while(t < l1 && s < l2)
{
ListNode *tmp = NULL;
if(list1->val <= list2->val)
{
tmp = list1;
list1 = list1->next;
++t;
} else {
tmp = list2;
list2 = list2->next;
++s;
}
if(tail) tail->next = tmp;
tail = tmp;
if(!head) head = tail;
}
while(t < l1)
{
if(tail) tail->next = list1;
tail = list1;
list1 = list1->next;
if(!head) head = tail;
++t;
}
while(s < l2)
{
if(tail) tail->next = list2;
tail = list2;
list2 = list2->next;
if(!head) head = tail;
++s;
}
}
if(tail) tail->next = NULL;
}
return head;
}
3. 链表归并排序的递归版本
ListNode * sortList(ListNode *head)
{
if(NULL == head || NULL == head->next)
return head;
ListNode *slow = head;
ListNode *fast = head->next;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
fast = slow->next;
slow->next = NULL;
slow = head;
slow = sortList(slow);
fast = sortList(fast);
ListNode *h = NULL;
ListNode *last = NULL;
while(slow && fast)
{
if(slow->val <= fast->val)
{
if(last) last->next = slow;
else h = slow;
last = slow;
slow = slow->next;
} else {
if(last) last->next = fast;
else h = fast;
last = fast;
fast = fast->next;
}
}
last->next = NULL;
if(slow) last->next = slow;
if(fast) last->next = fast;
return h;
}