题目:
Sort a linked list in O(n log n) time using constant space complexity.
这题还是比较纠结的,因为对于时间复杂度和空间复杂度都是有要求的。
时间复杂度是O(n log n)只能使用快速排序和归并排序。
空间复杂度是O(1)又必须是常数空间量。
对于快速排序,复习一下:
其思路是
1)用第一个数将当前数组/链表分为两部分,一部分小于这个数,另一部分大于这个数。
2)对小于这部分进行递归处理,步骤同1)。
3)对大于这部分进行递归处理,步骤同1)。
4)完毕。
对于归并排序,复习一下:
其思路是:
1)将数组/链表从中间截断,分为左右两部分。
2)递归中间截断两部分。
3)对小部分进行排序
4)合并每一个小部分。
本题,我从这三部分都进行了代码实现,对他们的时间进行了验证。
冒泡排序:其时间复杂度为O(n^2),在长度比较小时,满足要求,超过一定长度无法满足。
其空间复杂度为O(1);
快速排序,在本题链表中,其时间复杂度为n/2+O(n^2),(注:在数组中,其时间复杂度为O(n log n)~O(n^2),可能是本题没设计好。)相比冒泡排序,其复杂度是一样的。
其空间复杂度为O(log n)的递归调用,如果算上栈变量,比如左右指针这些,值为更大。
归并排序:本题链表,能解决此问题的就是归并排序了。
其时间复杂度:nlog(n) + n/2 log(n),因此其复杂度为O(n log n)满足要求。
空间复杂度:有两个递归调用,因此,空间复杂度为2*O(log n),也就是O (log n)。
具体代码思路:
冒泡排序:
1)两个循环,每两个值,进行值替换。也可以修改链表指针指向。两者难度相当,但在本题中,时间复杂度不满足要求。
快速排序:
1)遍历链表,将链表分为两个,一个小于第一个值,一个大于等于第一个值。
2)递归第一步。
3)将两个分开链表合并。
本题时间复杂度不满足要求,但是若是数组就可能满足了,因为数组可以双向遍历。所以最好的情况是分割点总是落在中间,这就满足情况,最坏的情况,一边只有一个,这时其时间复杂度相当于冒泡排序。
归并排序:
1)间隔遍历链表,找到中间点。(数组时不需要这步)。
2)递归处理隔断两部分。
3)将这两部分进行归并。
能确保隔断点总是在中间位置,所以时间复杂度是慢去要求的。其空间复杂度不太满足要求,不是一个常数复杂度。但本题已经被系统AC了。
代码见下,很多不必要的代码,但是都是知识点,供sherry多接触些排序算法:
// 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)
{
if (head == NULL)
{
return NULL;
}
if (head->next == NULL)
{
return head;
}
ListNode* r_head = head;
ListNode* head1 = head;
ListNode* head2 = head;
ListNode* end;
int count = 0;
while (head2->next && head2->next->next)
{
head1 = head1->next;
head2 = head2->next->next;
count++;
}
if (head2->next == NULL)
{
end = head2;
}
else if (head2->next->next == NULL)
{
end = head2->next;
}
if (count < 0)
{
bubblesort(head);
return head;
}
else if (count < 0)
{
qucksort(head,end);
return head;
}
else
{
head2 = head1->next;
head1->next = NULL;
head1 = head;
head = MergeList(MergeSort(head1),MergeSort(head2));
return head;
}
}
private:
ListNode* MergeSort(ListNode* head)
{
if (head == NULL)
{
return NULL;
}
else if (head->next == NULL)
{
return head;
}
ListNode* r_head = head;
ListNode* head1 = head;
ListNode* head2 = head;
while (head2->next && head->next->next)
{
head1 = head1->next;
head2 = head2->next->next;
}
head2 = head1->next;
head1->next = NULL;
head1 = head;
r_head = MergeList(MergeSort(head1),MergeSort(head2));
return r_head;
}
ListNode* MergeList(ListNode* prehead,ListNode* nexthead)
{
#if 0
ListNode* newtmp = new ListNode(0);
ListNode *tmp = newtmp;
if (prehead == NULL)
{
return nexthead;
}
if (nexthead == NULL)
{
return prehead;
}
while (prehead&&nexthead)
{
if (prehead->val < nexthead->val)
{
tmp->next= prehead;
prehead = prehead->next;
}
else
{
tmp->next = nexthead;
nexthead = nexthead->next;
}
tmp = tmp->next;
}
tmp->next = (prehead!=NULL?prehead:nexthead);
tmp = newtmp->next;
delete newtmp;
return tmp;
#endif
#if 1
ListNode *tmp;
if (prehead == NULL)
{
return nexthead;
}
if (nexthead == NULL)
{
return prehead;
}
if (prehead->val < nexthead->val)
{
tmp = prehead;
prehead = prehead->next;
}
else
{
tmp = nexthead;
nexthead = nexthead->next;
}
tmp = tmp->next;
tmp = MergeList(prehead,nexthead);
return tmp;
#endif
}
void bubblesort(ListNode* head)
{
ListNode* p = head;
while (p)
{
ListNode *pre = p->next;
while (pre)
{
if (pre->val < p->val)
{
int temp = p->val;
p->val = pre->val;
pre->val = temp;
}
pre = pre->next;
}
p = p->next;
}
}
void qucksort(ListNode* head,ListNode* end)
{
if (head == NULL)
{
return;
}
ListNode * head1,*end1,*head2,*end2;
head1 = end1 = head2 = end2 = NULL;
ListNode* pre1,*pre2,*p;
pre1 = pre2 = p = NULL;
int key = head->val;
p = head->next;
head->next = NULL;
while (p != NULL)
{
if (p->val < key)
{
if (!head1)
{
head1 = p;
pre1 = p;
pre1->next = NULL;
}
else
{
pre1->next = p;
pre1 = pre1->next;
pre1->next = NULL;
}
}
else
{
if (!head2)
{
head2 = p;
pre2 = p;
pre2->next = NULL;
}
else
{
pre2->next = p;
pre2 = pre2->next;
pre2->next = NULL;
}
}
}
end1 = pre1;
end2 = pre2;
qucksort(head1,end1);
qucksort(head2,end2);
if (end1&&head2)
{
end1->next = head;
head->next = head2;
head = head1;
end = end2;
}
else if (end1)
{
end1->next = head;
end = head;
head = head1;
}
else if (end2)
{
head->next = head2;
end = end2;
}
}
};