链表中的递归归并排序 Sort List
三点:
归并排序的整体思想
找到一个链表的中间节点的方法
合并两个已排好序的链表为一个新的有序链表
要求是时间复杂度是nlogn ,空间是常数级别。
在对数组进行排序时,归并排序时间复杂度为nlongn,空间复杂度为n;快速排序的时间复杂度是n~nlogn之间,空间复杂度是logn;堆排序的时间复杂度是nlogn,空间复杂度是1.但是在对链表进行排序时,归并排序可以实现常数的空间复杂度,而且时间复杂度依然是nlogn。
归并排序法:因为原来使用归并时,空间复杂度都是 O(N)的,需要复制出相等的空间来进行赋值归并。对于链表,实际上是可以实现常数空间占用的(链表的归并 排序不需要额外的空间)。利用归并的思想,递归地将当前链表分为两段,然后对两段分别进行递归调用排序方法,然后合并(merge),分两段的方法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,直到快的走到了末尾,然后慢的所在位置就是中间位置,这样就分成了两段。
#include <stdlib.h>
#include<iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x): val(x), next(NULL) {}
};
ListNode *findMiddle(ListNode *head)
{
ListNode *middle = head;
ListNode *runner = head->next;
while(runner != NULL && runner->next != NULL)
{
middle = middle->next;
runner = runner->next->next;
}
return middle;
}
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
{
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
ListNode *pre = new ListNode(0);
ListNode *head = pre;
while (l1 != NULL && l2 !=NULL)
{
if(l1->val > l2->val)
{
head->next = l2;
l2 = l2->next;
}
else
{
head->next = l1;
l1 = l1->next;
}
head = head->next;
}
if (l1 == NULL)
{
head->next = l2;
}
if (l2 == NULL)
{
head->next = l1;
}
return pre->next;
}
ListNode *sortList(ListNode *head)
{
if (head == NULL || head->next == NULL)
{
return head;
}
ListNode *middle = findMiddle(head);
ListNode *right = sortList(middle->next);
middle->next = NULL;
ListNode *left = sortList(head);
return mergeTwoLists(left, right);
}
int main()
{
ListNode n1(3), n2(4), n3(2), n4(1), n5(5);
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
ListNode *head = NULL;
head = sortList(&n1);
ListNode *head1;
while (head != NULL)
{
cout << head ->val << endl;
head = head ->next;
}
return 0;
}
参考链接:https://www.cnblogs.com/qiaozhoulin/p/4585401.html
参考链接:https://blog.csdn.net/weixin_39688949/article/details/78472246?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1