对一个链表进行排序,且时间复杂度为O(nlongn),空间复杂度为常量。
首先一看到O(nlongn)的排序就应该想到归并排序和快速排序。
归并排序:
在一般情况下,归并排序的空间复杂度为O(n)的,需要复制出相等空间来进行赋值排序。但实际上,对于链表是可以实现常数空间的。
利用归并排序的思想递归的将当前链表分为两段,然后merge,分两段的方法:
使用fast-slow法,用两个指针,一个每次走一步,另一个每次走两步,之道走到末尾,慢指针指向的就是中间位置。这样就分成了两段。
快速排序:
当然,这里也可以用快速排序,但是由于快速排序它的元素交换次数太多了就可能会影响时间效率。所以这里适合采用归并排序。
/**********************************************************
* Author : oyjb
* Email : jbouyang@126.com
* Last modified : 2015-06-25 13:51
* Filename : sortList.cpp
* Description :
* *******************************************************/
/**Definition of ListNode.*/
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x),next(NULL);
};
class Solution
{
public:
ListNode *sortList(ListNode *head)
{
if (!head || !head->next)//头结点为空或者只有一个结点
return head;
return mergeSort(head);
}
ListNode* mergeSort(ListNode *head)
{
if (!head || !head->next)
return head;
ListNode *p = head,*q = head,*pre = NULL;
/*
* 找到链表中间节点
* 让p每次走一步,q每次走两步
* 并且记录p的前驱节点
*/
while (q && q->next != NULL)
{
q = q->next->next;
pre = p;//记录p的前躯
p = p->next;
}
pre->next = NULL;//从p节点处断开
//recusive
ListNode *lhalf = mergeSort(head);
ListNode *rhalf = mergeSort(p);
return merge(lhalf,rhalf);
}
ListNode* merge(ListNode *lh,ListNode *rh)
{
ListNode *temp = new ListNode(0);
ListNode *p = temp;
while (lh != NULL && rh != NULL)
{
if (lh->val <= rh->val)
{
p->next = lh;
lh = lh->next;
}
else
{
p->next = rh;
rh = rh->next;
}
p = p->next;
}
if (!lh) //如果左链表为空,则添加右链表到尾部,反之
p->next = rh;
else
p->next = lh;
p = temp->next;
temp->next = NULL;
delete temp;
return p;
}
};