Sort a linked list in O(n log n) time using constant space complexity.
问题:对一个单列表排序,要求时间复杂度为 O(n*logn),额外空间为 O(1)。
O(n*logn) 时间排序算法,无法是 quick sort, merge sort, head sort。quick sort 需要灵活访问前后元素,适合于数组,merge sort 只需要从左到右扫过去即可,可用于列表结构。
- 当列表元素个数大于2时,将列表拆分为左右对半的两个子列表,对左右子列表分别排序,然后合并。
- 当列表元素个数小于等于2 时,直接对列表元素比较排序。
第一步中的合并操作,实际上另一个LeetCode题目 Merge Two Sorted Lists
需要注意的是,由于是单向列表,为了方便操作元素位置,每次比较操作比较的是指针的下一个元素,详情见 sortmerge 函数。
1 /** 2 * p 表示父节点 3 * ll, lr 分别表示左半列表的父节点,右半列表的父节点 4 * 5 */ 6 ListNode* sortmerge(ListNode* p, int len){ 7 8 if (len <= 1) { 9 return p; 10 } 11 12 if (len == 2) { 13 if (p->next->val > p->next->next->val) { 14 int tmp = p->next->val; 15 p->next->val = p->next->next->val; 16 p->next->next->val = tmp; 17 } 18 return p; 19 } 20 21 int lenL = len / 2; 22 int lenR = len - lenL; 23 24 ListNode* ll = p; 25 26 ll = sortmerge(ll, lenL); 27 28 ListNode* lr = p; 29 30 for (int i = 0 ; i < lenL; i++) { 31 lr = lr->next; 32 } 33 34 lr = sortmerge(lr, lenR); 35 36 37 while (ll != lr && lenR > 0) { 38 if (ll->next->val <= lr->next->val) { 39 ll = ll->next; 40 }else{ 41 ListNode* next2 = lr->next; 42 lr->next = lr->next->next; 43 next2->next = ll->next; 44 ll->next = next2; 45 lenR--; 46 } 47 } 48 49 return p; 50 } 51 52 ListNode* sortList(ListNode* head) { 53 54 55 ListNode* node = head; 56 57 int cnt = 0; 58 while (node != NULL) { 59 cnt++; 60 node = node->next; 61 } 62 63 ListNode* p = new ListNode(0); 64 p->next = head; 65 66 p = sortmerge(p, cnt); 67 68 head = p->next; 69 70 return head; 71 }
参考资料: