排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
提示:
链表中节点的数目在范围 [0, 5 * 10 ^4] 内
-10 ^5 <= Node.val <= 10 ^5
进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
思路:链表的排序跟数组一样也有冒泡插入交换、其中O(n log n)的有快排、归并、堆排序。
堆排序和归并是O(n log n)的复杂度,这道题使用这两种都可以 过,但是快排的复杂度取决于所选的基准值、如果选第一个元素为基准值,当链表是高度有序的时候快排是O(n^2)的复杂度,所以这道题用快排需要取链表的中间元素为基准值。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
void QuickSort(ListNode *pBegin,ListNode *pEnd){//快排的运行函数
if(pBegin!=pEnd){//链表为空递归结束
ListNode *slow=pBegin;//这里用两个指针一个慢,一个快,获取量表中间节点
ListNode *fast=pBegin->next;//快指针
while(fast!=pEnd&&fast->next!=pEnd){//快指针到pEnd或快指针的下一个节点为pEnd时结束(避免出现空指针)
fast=fast->next->next;//快指针一次移动两格,满指针一次移动一个,快指针移动到最后时,慢指针移动到中间
slow=slow->next;
}
int t=slow->val;//交换链表中间值和头节点的值
slow->val=pBegin->val;
pBegin->val=t;
ListNode *mid=GetMid(pBegin,pEnd);//获取划分的节点位置
QuickSort(pBegin,mid);//递归处理
QuickSort(mid->next,pEnd);
}
}
ListNode * GetMid(ListNode *pBegin,ListNode *pEnd){//获取结点位置函数
ListNode *p=pBegin;
ListNode *q=p->next;
int t,key=pBegin->val;//存放基准值
while(q!=pEnd){
if(q->val<key){//如果q结点的值小于基准值
p=p->next;//p结点先向后移动一个结点
t=p->val;//交换p,q结点的值
p->val=q->val;
q->val=t;
}
q=q->next;//q结点移动
}
t=p->val;//交换p结点和pBegin结点的值
p->val=pBegin->val;
pBegin->val=t;
return p;//返回pBegin结点最后位置
}
ListNode* sortList(ListNode* head) {//初始化,进行快排
if(head==NULL) return head;
ListNode *pEnd;
ListNode *pBegin;
pBegin=head;
pEnd=NULL;
QuickSort(pBegin,pEnd);
return head;
}
};