题目来源148排序链表
一、思路
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。举例:
例1:
输入: 4->2->1->3
输出: 1->2->3->4
例2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
对单链表进行排序,我们八九不离十可以往快速排序、归并排序等排序算法上面想(因为时间复杂度提示了我们)。
1.1 知识点
请看实现:
ListNode* sortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode dummy = ListNode(0);
dummy.next = head;
int length = findSize(head);
for (int gap = 1; gap < length; gap <<= 1) {
ListNode *tail = &dummy, *current = dummy.next; //tail用于重连链表,current用于遍历链表
while (current) {
ListNode *left = current, *right;
right = split(left, gap); //切下左归并段
current = split(right, gap); //切下右归并段
tail->next = twoWayMerge(left, right);
while (tail->next) {
tail = tail->next;
}//tail指向归并段的最后一个结点
}//以步长为gap遍历链表
}//控制每次遍历链表时的步长
return dummy.next;
}
int findSize(ListNode *head) {
int length = 0;
while (head) { length++; head = head->next; }
return length;
}//返回链表长度
ListNode *split(ListNode *head, int gap) {
ListNode *prev = head;
while (--gap && prev) {
prev = prev->next;
}
if (!prev) return nullptr;
ListNode *save = prev->next; //暂存第gap+1个结点
prev->next = nullptr; //断链
return save; //返回第gap+1个结点
}//切下head为头指针的链表前gap个结点,返回第gap+1个头结点
ListNode *twoWayMerge(ListNode *l1, ListNode *l2) {
ListNode dummy = ListNode(0), *prev = &dummy; //使用哑结点统一操作
while (l1 && l2) {
if (l1->val < l2->val) {
prev->next = l1;
prev = l1;
l1 = l1->next;
}
else {
prev->next = l2;
prev = l2;
l2 = l2->next;
}
}
prev->next = l1 != nullptr ? l1 : l2;
return dummy.next;
}//返回归并段的头指针