排序链表

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4
示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

递归版:(不符合空间复杂度要求)

题目要求时间空间复杂度分别为O(nlogn)O(nlogn)和O(1)O(1),根据时间复杂度我们自然想到二分法,从而联想到归并排序;

对数组做归并排序的空间复杂度为 O(n),分别由新开辟数组O(n)和递归函数调用O(logn)组成,而根据链表特性

数组额外空间:链表可以通过修改引用来更改节点顺序,无需像数组一样开辟额外空间;
递归额外空间:递归调用函数将带来O(logn)的空间复杂度,因此若希望达到O(1)空间复杂度,则不能使用递归
通过递归实现链表归并排序,有以下两个环节:

分割 cut 环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归 cut 时,链表片段拥有正确边界);
我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。
找到中点 slow 后,执行 slow.next = None 将链表切断。
递归分割时,输入当前链表左端点 head 和中心节点 slow 的下一个节点 tmp(因为链表是从 slow 切断的)。
cut 递归终止条件: 当head.next == None时,说明只有一个节点了,直接返回此节点。
合并 merge 环节: 将两个排序链表合并,转化为一个排序链表。
双指针法合并,建立辅助ListNode h 作为头部。
设置两指针 left, right 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。
返回辅助ListNode h 作为头部的下个节点 h.next。
时间复杂度 O(l + r),l, r 分别代表两个链表长度。
当题目输入的 head == None 时,直接返回None。

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode* sortList(ListNode* head) {
12         if (head == nullptr || head->next == nullptr)
13             return head;
14         ListNode *fast = head->next, *slow = head;
15         //快慢指针找到链表中点
16         while (fast!=nullptr&&fast->next!=nullptr)
17         {
18             slow = slow->next;
19             fast = fast->next->next;
20         }
21         //cut链表
22         ListNode *tmp = slow->next;
23         slow->next = nullptr;
24 
25         ListNode *left = sortList(head);
26         ListNode *right = sortList(tmp);
27 
28         ListNode *h = new ListNode(0);
29         ListNode *res = h;
30         while (left!=nullptr&&right!=nullptr)
31         {
32             if (left->val < right->val)
33             {
34                 h->next = left;
35                 left = left->next;
36             }
37             else
38             {
39                 h->next = right;
40                 right = right->next;
41             }
42             h = h->next;
43         }
44         h->next = left != nullptr ? left : right;
45         return res->next;
46     }
47 };

非递归版:(由下往上处理)

 1 class Solution {
 2 public:
 3     ListNode* sortList(ListNode* head) {
 4         ListNode dummyHead(0);
 5         dummyHead.next = head;
 6         auto p = head;
 7         int length = 0;
 8         while (p) {
 9             ++length;
10             p = p->next;
11         }
12         
13         for (int size = 1; size < length; size <<= 1) {
14             auto cur = dummyHead.next;
15             auto tail = &dummyHead;
16             
17             while (cur) {
18                 auto left = cur;
19                 auto right = cut(left, size); // left->@->@ right->@->@->@...
20                 cur = cut(right, size); // left->@->@ right->@->@  cur->@->...
21                 
22                 tail->next = merge(left, right);
23                 while (tail->next) {
24                     tail = tail->next;
25                 }
26             }
27         }
28         return dummyHead.next;
29     }
30     
31     ListNode* cut(ListNode* head, int n) {
32         auto p = head;
33         while (--n && p) {
34             p = p->next;
35         }
36         
37         if (!p) return nullptr;
38         
39         auto next = p->next;
40         p->next = nullptr;
41         return next;
42     }
43     
44     ListNode* merge(ListNode* l1, ListNode* l2) {
45         ListNode dummyHead(0);
46         auto p = &dummyHead;
47         while (l1 && l2) {
48             if (l1->val < l2->val) {
49                 p->next = l1;
50                 p = l1;
51                 l1 = l1->next;       
52             } else {
53                 p->next = l2;
54                 p = l2;
55                 l2 = l2->next;
56             }
57         }
58         p->next = l1 ? l1 : l2;
59         return dummyHead.next;
60     }
61 };
原文地址:https://www.cnblogs.com/wangshaowei/p/11383539.html