给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路一:首先利用快慢指针将链表找到中间节点。如果是奇数节点我们就从正中间那个节点那个位置断开。如果是偶数个节点我们就从刚好能从链表分成两个相同数量的节点位置处断开。分别对左右子序列进行归并排序。(递归版)不符合题目要求
/**
* 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:
ListNode* sortList(ListNode* head) {
//处理平凡情况
if(head == nullptr || head->next == nullptr)
return head;
ListNode* fast = head->next;
ListNode* slow = head;
while(fast != nullptr && fast->next !=nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
ListNode* temp = slow->next;// 保存链表断开位置的下一索引位置
slow->next = nullptr;//断开链表
ListNode* left = sortList(head);
ListNode* right = sortList(temp);
ListNode* dummyHead = new ListNode(0);
ListNode* cur = dummyHead;
while(left != nullptr && right != nullptr)
{
if(left->val < right->val)
{
cur->next = left;
left = left->next;
}
else
{
cur->next = right;
right = right->next;
}
cur = cur->next;
}
if(left)//如果左边节点有剩余
cur->next = left;
if(right)
cur->next = right;
return dummyHead->next;
}
};
迭代版归并排序:
利用迭代来模拟自底向上的归并排序:
/**
* 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:
ListNode* sortList(ListNode* head) {
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* cur = head;
int length = 0;
while(cur)
{
++length;//先统计出链表的长度
cur = cur->next;
}
for(int size = 1;size < length;size <<= 1)
{
cur = dummyHead->next;
ListNode* tail = dummyHead;
while(cur)
{
ListNode* left = cur;
ListNode* right = cut(left,size);
cur = cut(right,size);
tail->next = merge(left,right);
while(tail->next)//tail指向已经和并子链表的末尾(方便将合并的子链表连接)
{
tail = tail->next;
}
}
}
return dummyHead->next;
}
//cut(l, n),,即断链操作。它表示,将链表 l 切掉前 n 个节点,并返回后半部分的链表头
ListNode* cut(ListNode* head,int n)
{
ListNode* cur = head;
while(--n && cur)
{
cur = cur->next;
}
if(!cur)
{
return nullptr;
}
ListNode* next = cur->next;
cur->next = nullptr;
return next;
}
ListNode* merge(ListNode* l1,ListNode* l2)
{
ListNode* dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
while(l1 && l2)
{
if(l1->val < l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
if(l1)
cur->next = l1;
if(l2)
cur->next = l2;
return dummyHead->next;
}
};
快排版本:过几天来看。今天思路混乱