题目:https://oj.leetcode.com/problems/sort-list/
Sort a linked list in O(n log n)
time using constant space complexity.
思路:
对链表进行排序,并且要求是O(n log n)的时间复杂度,同事要求使用常量排序空间,可行的方法包括归并排序、快速排序。进行快速排序的时候,需要不断地调整链表之间的指针顺序,最好是采用新版算法导论里面的partition方法;如果是归并排序的话,那么有两种方式来实现。
第一种是传统的归并排序,进行排序的时候,由于需要对链表进行2分,因此可以采用快慢链表的方式,具体代码如下:
/**
* 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) {
lmerge_sort(head);
}
ListNode* lmerge_sort(ListNode*start)
{
if(start == NULL || start->next == NULL)
{
return start;
}
ListNode *p = start;
ListNode *q = start;
ListNode *pre = NULL;
while (q != NULL && q->next != NULL)
{
q = q->next->next;//采用的快慢指针,实现对链表的二分
pre = p;
p = p->next;
}
pre->next = NULL;
ListNode*head1 = lmerge_sort(start);
ListNode *head2 = lmerge_sort(p);
return lmerge(head1,head2);
}
ListNode* lmerge(ListNode*head1,ListNode*head2)
{
ListNode *head;
ListNode *p;
if(head1 == NULL)
{
return head2;
}
if(head2 == NULL)
{
return head1;
}
if(head1->val < head2->val)
{
head = head1;
head1 = head1->next;
}
else
{
head = head2;
head2 = head2->next;
}
p = head;
while (head1 != NULL &&head2 != NULL)
{
if(head1->val < head2->val)
{
p->next = head1;
head1= head1->next;
}
else
{
p->next = head2;
head2= head2->next;
}
p = p->next;
}
if(head1 != NULL)
{
p->next = head1;
}
if(head2 != NULL)
{
p->next = head2;
}
return head;
}
};
第二种归并排序的思路来自于STL里面对list进行排序的方法,采用缓冲列表的方式,采用一个大小为64的数组,就可以对至多2^64-1的链表进行排序,这个数据的范围基本上可以满足所有的排序需求。具体代码如下:
class Solution {
public:
ListNode *sortList(ListNode *head) {
int feet= 0;
const int MAX = 64;
ListNode *mlist[MAX]= {NULL};//链表缓冲区
ListNode *carry = NULL;
while (head != NULL)
{
int itp = 0;
// cout << head->val <<" ";
carry = slice(head);
while (itp < feet&& mlist[itp] != NULL)
{
//cout << "asd"<<endl;
// print(mlist[itp]);
mergelist(carry,mlist[itp]);
// cout << "asd"<<endl;
itp ++;
}
mergelist(carry,mlist[itp]);
myswap(carry,mlist[itp]);
if(itp == feet)
{
feet ++;
}
}
// cout << "rnd;"<<endl;
carry = NULL;
for(int i = 0;i < feet;i ++)
{
mergelist(carry,mlist[i]);
}
return carry;
}
ListNode * slice(ListNode *&head)
{
ListNode * tmp = head;
head = head->next;
tmp->next = NULL;
return tmp;
}
void mergelist(ListNode*&qhead,ListNode *&phead)
{
ListNode *thead = new ListNode(0);
ListNode *head1 = qhead;
ListNode *head2 = phead;
ListNode *p = thead;
while(head1 != NULL && head2 != NULL)
{
if(head1->val < head2->val)
{
p->next = head1;
head1 = head1->next;
p = p->next;
}
else
{
p->next = head2;
head2 = head2->next;
p = p->next;
}
}
while(head1 != NULL)
{
p->next = head1;
p = p->next;
head1 = head1->next;
}
while(head2 != NULL)
{
p->next = head2;
p = p->next;
head2 = head2->next;
}
p->next = NULL;
qhead = thead->next;
phead = NULL;
delete thead;
}
void myswap(ListNode * &a,ListNode *&b)
{
ListNode * tmp = a;
a = b;
b = tmp;
}
};
第二种思路很巧妙,理解的时候有一定困难,尽可能的多在纸上画画。