148. Sort List
Sort a linked list in O(n log n) time using constant space complexity.
一、归并:
主要考察3个知识点,
知识点1:归并排序的整体思想
知识点2:找到一个链表的中间节点的方法
知识点3:合并两个已排好序的链表为一个新的有序链表
归并排序的基本思想是:
1、找到链表的middle节点,
2、然后递归对前半部分和后半部分分别进行归并排序,
3、最后对两个以排好序的链表进行Merge。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* merge(ListNode* head, ListNode* fast)
{
ListNode hhead(-1);
ListNode* p = &hhead;
while (head || fast)
{
if (!head)
{
p->next = fast;
break;
}
else if (!fast)
{
p->next = head;
break;
}
if (head->val < fast->val)
{
p->next = head;
head = head->next;
}
else
{
p->next = fast;
fast = fast->next;
}
p = p->next;
}
return hhead.next;
}
ListNode* sortList(ListNode* head)
{
if (!head || !head->next)
return head;
else if (!head->next->next)
{
if (head->val > head->next->val)
{
swap(head->val, head->next->val);
}
return head;
}
//找到中间结点
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = NULL;
//递归前半部分和后半部分
head = sortList(head);
fast = sortList(fast);
//最后merge两个
head = merge(head , fast);
return head;
}
};
二、链表快速排序:
你可能会诧异,怎么会是快排?快排不是需要一个指针指向头,一个指针指向尾,然后两个指针相向运动并按一定规律交换值,最后找到一个支点使得支点左边小于支点,支点右边大于支点吗?如果是这样的话,对于单链表我们没有前驱指针,怎么能使得后面的那个指针往前移动呢?所以这种快排思路行不通滴,如果我们能使两个指针都往next方向移动并且能找到支点那就好了。怎么做呢?
接下来我们使用快排的另一种思路来解答。我们只需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次支点的寻找。如下图所示:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* sortList(ListNode* head)
{
ListNode* endpoint = head;
while (endpoint->next)
endpoint = endpoint->next;
QuickSort(head, endpoint);
return head;
}
private:
void QuickSort(ListNode* pBeign, ListNode* pEnd)
{
if (pBeign != pEnd)
{
ListNode* partion = GetPartion(pBeign, pEnd);
QuickSort(pBeign, partion);
if (partion->next)
QuickSort(partion->next, pEnd);
}
}
ListNode* GetPartion(ListNode* pBegin, ListNode* pEnd)
{
int key = pBegin->val;
ListNode* p = pBegin;
ListNode* q = p->next;
while (q != pEnd->next)
{
if (q->val < key)
{
p = p->next;
swap(p->val, q->val);
}
q = q->next;
}
swap(p->val, pBegin->val);
return p;
}
};