题目内容:
Sort a linked list in O(n log n) time using constant space complexity.
根据给出的时间复杂度,可以想到满足的排序方法有:
1. 快速排序
2. 堆排序
3. 归并排序
再考虑空间复杂度:
1. 快速排序主要要实现partition算法,在数组中它实现的算法复杂度为O(n),利用链表,同样可以在O(n)时间内实现,且不需要额外的空间,可行。
2. 堆排序需要能够在O(1)时间内获得某个节点的父节点或者子节点,因此需要有一个类似于数组的容器装。而这里本身链表就会有O(n)的空间装指针,将这些指针装入priority_queue中不需要额外的开辟空间,因此也是可行的
3. 归并排序在数组中本来需要开辟O(n)的空间存储合并后的节点,但是在链表中可以在原地实现,这在之前的Leetcode题中已经解过,因此归并排序也是可行的。
下面给出这三种方法的代码实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
struct ListCompare {
bool operator()(ListNode *n1, ListNode *n2) {
return n1->val < n2->val;
}
};
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head == NULL)
return NULL;
//quickSort(head);
//mergeSort(head);
heapSort(head);
return head;
}
void heapSort(ListNode *&head) {
ListNode *p(head);
priority_queue<ListNode *, vector<ListNode *>, ListCompare> ListHeap;
while(p != NULL) {
ListHeap.push(p);
p = p->next;
}
head = NULL;
// 这里使用了最大堆,前插法构建链表
while(!ListHeap.empty()) {
ListNode *temp = ListHeap.top();
ListHeap.pop();
temp->next = head;
head = temp;
}
}
void mergeSort(ListNode *&head) {
if(head == NULL || head->next == NULL)
return;
ListNode *mid = getMidPoint(head);
mergeSort(head);
mergeSort(mid);
head = mergeList(head, mid);
}
// return the mid point of list and split the list
ListNode *getMidPoint(ListNode* head) {
if(head == NULL)
return NULL;
ListNode *one(head), *two(head), *pre(NULL);
while(two != NULL && two->next != NULL) {
pre = one;
one = one->next;
two = two->next->next;
}
pre->next = NULL;
return one;
}
ListNode *mergeList(ListNode *l1, ListNode *l2) {
if(l1 == NULL && l2 == NULL)
return NULL;
if(l1 == NULL)
return l1;
if(l2 == NULL)
return l2;
ListNode *p1(l1), *p2(l2), *head = new ListNode(0), *p = head;
while(p1 != NULL && p2 != NULL) {
if(p1->val < p2->val) {
p->next = p1;
p1 = p1->next;
}
else {
p->next = p2;
p2 = p2->next;
}
p = p->next;
p->next = NULL;
}
if(p1 != NULL)
p->next = p1;
else if(p2 != NULL)
p->next = p2;
p = head;
head = head->next;
p->next = NULL;
delete p;
return head;
}
void quickSort(ListNode *&head) {
partition(head, NULL);
}
// end is not included in the list
void partition(ListNode *&start, ListNode *end) {
//printList(start, end);
if(start == end || start->next == end)
return;
ListNode *pts = start, *pte = start, *small = start, *large = end;
while(small->next != end) {
if(small->next->val > pts->val) {
ListNode *temp = small->next;
small->next = small->next->next;
temp->next = large;
large = temp;
}
else if(small->next->val == pts->val) {
ListNode *temp = small->next;
small->next = small->next->next;
temp->next = pts;
pts = temp;
}
else {
small = small->next;
}
}
small->next = pts;
small = pte->next;
partition(small, pts);
partition(large, end);
pte->next = large;
start = small;
}
};