Sort a linked list in O(n log n) time using constant space complexity. http://oj.leetcode.com/problems/sort-list/
O (n log n)的排序算法有快速排序、归并排序等,于是一开始用快速排序算法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
if (head==NULL || head->next==NULL)
return head;
qsort(head, NULL);
return head;
}
private:
template<typename T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
void qsort(ListNode *head, ListNode *tail) {
if (head == tail || head->next == tail)
return;
ListNode *min = head, *p = head->next;
while (p != tail) {
if (p->val <= head->val) {
min = min->next;
swap(min->val, p->val);
}
p = p->next;
}
swap(head->val, min->val);
if (min != head)
qsort(head, min);
if (min != tail)
qsort(min->next, tail);
}
};
但是运行到最后一个case时超时,因为那个case数字都是1、2、3,快排不仅要每次比较数字大小,还要经常交换两个节点的值,而且是快排最坏的情况,每次分割成很不均匀的两部分,耗时大。网上看了下别人用归并排序,于是写了归并排序如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
// merge sort
if (head == NULL)
return head;
int len = 0;
ListNode *curr = head;
while (curr != NULL) {
curr = curr->next;
++len;
}
if (len == 1)
return head;
int midLen = len/2-1;
int index = 0;
curr = head;
while (index < midLen) {
++index;
curr = curr->next;
}
ListNode *firstHead = head;
ListNode *secondHead = curr->next;
curr->next = NULL; //使第一个链表结尾为空
firstHead = sortList(firstHead); //归并排序前半部分
secondHead = sortList(secondHead); //归并排序后半部分
ListNode *newHead = NULL;
//合并两个有序链表
while (firstHead != NULL && secondHead != NULL) {
if (firstHead->val < secondHead->val) {
if (newHead == NULL) {
newHead = firstHead;
curr = newHead;
}
else {
curr->next = firstHead;
curr = curr->next;
}
firstHead = firstHead->next;
} else{
if (newHead == NULL) {
newHead = secondHead;
curr = newHead;
} else{
curr->next = secondHead;
curr = curr->next;
}
secondHead = secondHead->next;
}
}
if (firstHead != NULL) { //连接第1个链表剩余部分
curr->next = firstHead;
}
else if (secondHead != NULL) { //连接第2个链表剩余部分
curr->next = secondHead;
}
return newHead;
}
};
用归并排序求链表排序问题比较合适,因为不像快排需要很多交换赋值操作,归并排序只是改变节点的next值,而且这里用链表归并排序用的空间是O(1)的,如果用数组就要O(n).