链表排序
问题:排序链表
要求:对链表进行排序,要求 时间复杂度O(n logn) 空间复杂度常数级别
PS: 学习链表寻找中点的方法
解法一:归并排序的递归解法(空间复杂度不符合,递归栈使用空间)
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) { return (head == nullptr) ? nullptr : mergeSort(head); } private: ListNode * findMid(ListNode * head) { ListNode * slow = head; ListNode * fast = head; while (fast->next != nullptr && fast->next->next != nullptr) { slow = slow->next; fast = fast->next->next; } // split the list into two parts ListNode * newHead = slow->next; slow->next = nullptr; return newHead; } ListNode * mergeTwoLists(ListNode * l1, ListNode * l2) { if (l1 == nullptr) return l2; if (l2 == nullptr) return l1; if (l1->val < l2->val) { l1->next = mergeTwoLists(l1->next, l2); return l1; } else { l2->next = mergeTwoLists(l1, l2->next); return l2; } } ListNode * mergeSort(ListNode * head) { if (head->next == nullptr) return head; ListNode * mid = findMid(head); ListNode * l1 = mergeSort(head); ListNode * l2 = mergeSort(mid); return mergeTwoLists(l1, l2); } };
解法二:快排的迭代解法(空间复杂度不符合,递归栈使用空间)
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: void quickSortList(ListNode* pre, ListNode* head, ListNode* tail) { if (head != tail && head->next != tail) { ListNode * mid = partition(pre, head, tail); quickSortList(pre, pre->next, mid); quickSortList(mid, mid->next, tail); } } ListNode * partition(ListNode* pre, ListNode* start, ListNode* end) { int key = start->val; ListNode * head1 = new ListNode(-1); ListNode * head2 = new ListNode(-1); ListNode * s = head1; ListNode * e = head2; for (ListNode *node = start->next; node != end; node = node->next) { if (node->val <= key) { s->next = node; s = node; } else { e->next = node; e = node; } } e->next = end; s->next = start; start->next = head2->next; pre->next = head1->next; return start; } ListNode* sortList(ListNode* head) { if (head == nullptr || head->next == nullptr) { return head; } ListNode * pre = new ListNode(0); quickSortList(pre, head, nullptr); return pre->next; } };
解法三:归并排序的迭代解法
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: //cut n个节点,然后返回剩下的链表的头节点 ListNode * cut(ListNode * head, int n) { ListNode * p = head; while (--n && p) { p = p->next; } if (p == nullptr) { return nullptr; } ListNode *subc = p->next; p->next = nullptr; return subc; } //迭代合并链表 ListNode * merge(ListNode* l1, ListNode* l2) { ListNode * pre = new ListNode(0); ListNode * p = pre; while (l1 && l2) { if (l1->val < l2->val) { p->next = l1; l1 = l1->next; } else { p->next = l2; l2 = l2->next; } p = p->next; } p->next = l1 ? l1 : l2; return pre->next; } ListNode* sortList(ListNode* head) { if (head == nullptr || head->next == nullptr) { return head; } //先求得链表的长度,然后根据长度来cut int length = 0; ListNode * p = head; while (p) { length++; p = p->next; } //第一次cut 1,然后根据归并的思路,cut的大小依次*2,边界条件为size<length,因为size==n表示的是链表的每个长度为n的段已经是有序的了,执行循环的目的就是把有序的长度为n的段连起来,因此当size>=length时,表示长度为size的段已经有序,即原链表已经归并完成,结束循环。只有当size<length时才表明没有归并完成,进入循环继续归并 ListNode * pre = new ListNode(0); pre->next = head; for (int size = 1; size< length; size *= 2) { //cur表示待分割链表的第一个节点,tail表示已经合并好的链表的最后一个节点 ListNode * cur = pre->next; ListNode * tail = pre; while (cur) { ListNode * left = cur; ListNode * right = cut(left, size); cur = cut(right, size); tail->next = merge(left, right); while (tail->next) tail = tail->next; } } return pre->next; } };