力扣-每日一题20201121-148. 排序链表
解题思路:
时间复杂度为O(nlogn)的排序算法有归并排序、堆排序和快排**,快排的时间复杂度最坏达到O(n²)。
其中最适合链表的排序算法是归并排序,归并排序有两种实现方式:
-
一种是自顶向下的递归实现,空间复杂度为***O(logn)***
-
一种是自底向上的实现,空间复杂度为***O(1)***
自顶向下方法实现思想
-
使用快慢指针找到链表的中点,将链表拆分为两个部分。
-
对两个子链表进行递归排序。
-
将有序的两个子链表进行合并。
自底向上方法实现思想
- 使用min_length来表示每次需要合并的子链长度,初始值为1。
- 将链表以min_length为长度进行拆分,最后一个子链可以不足min_length。合并后的链表长度为2*min_length。
- 将min_length翻倍,重复第二部的操作,直至2*min_length的值大于等于length。
代码:
/**
* 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) //判断链表是否为空
return nullptr;
int len = 0;
ListNode* t = head;
while(t!=nullptr){ // 计算链表的长度
len++;
t = t->next;
}
int min_length = 1;
ListNode* t_head = new ListNode(0,head); // 充当头结点
while(min_length < len){
ListNode *pre = t_head, *curr = t_head->next;
while(curr!=nullptr){
ListNode *head1 = curr; // 第一个链表的头结点
for(int i =1;i<min_length&&curr->next!=nullptr;i++){// 找到第一个子链的末尾
curr = curr->next;
}
ListNode *head2 = curr->next;// 第二个链表的头结点
curr->next = nullptr; //将第一个链表的末尾设置为空
curr = head2;
for(int i =1;i<min_length&&curr!=nullptr&&curr->next!=nullptr;i++){// 找到第二个子链的末尾
curr = curr->next;
}
ListNode *next = nullptr;
if(curr!=nullptr){ // 如果不是链表的结尾
next = curr->next; //保存后续进程的头结点
curr->next = nullptr;//将第二个链表的末尾设置为空
}
ListNode* merged = mergeTwoLists(head1, head2);
pre->next = merged; // 保存已经有序的链表
while (pre->next != nullptr) { // 进到以有序的链表的末尾
pre = pre->next;
}
curr = next; //下一次合并的链表的第一个结点
}
min_length <<=1; // min_length乘2
}
return t_head->next;
}
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { //力扣第21题. 合并两个有序链表
ListNode* l =new ListNode(0);
ListNode* t = l;
while(l1 != nullptr && l2!=nullptr){
if(l1->val > l2->val){
t->next = l2;
l2 = l2->next;
}else{
t->next = l1;
l1 = l1->next;
}
t = t->next;
}
while(l1 != NULL){
t->next = l1;
t = t->next;
l1 = l1->next;
}
while(l2 != NULL){
t->next = l2;
t = t->next;
l2 = l2->next;
}
return l->next;
}
};