思路:
相信大家對數組的歸並排序非常了解,不了解的可以自己百度。本博客只是對單鏈表的歸並排序中的小細節進行闡述.
這個圖,就是一種分治的方式,當遞歸到最底層時,對兩個數進行排序,當回到上一層,其實就得到了,兩個有序的序列,然后再對這兩個序列進行排序並合並成一個新的序列。這樣一層一層的重復相同的操作,就可以得到整個序列的排序!
重點:
對於來兩個有序序列的合並,是這樣合並的。
先申請一個局部的節點(相當於 表頭 ):然后,比較左右鏈表的最小值,誰最小就把誰拆下來,放在新的鏈表后面。值得注意的是:全過程只是申請了一個表頭節點的內存。這一點在不計算遞歸所使用的內存的話,空間復雜度為O(1)
下面看圖解:
然后,注意一下代碼中p的維護,因為p是新鏈表的尾指針!
代碼:
struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; class Solution { public: ListNode *sortList(ListNode *head){ if (!head || !head->next) return head; //空鏈表和只有一個元素的鏈表不需要排序 ListNode *p = head, *q = head->next; //找到鏈表的中間位置 while (q&&q->next){ //快慢指針,注意必須前兩步存在 p = p->next; q = q->next->next; } ListNode *left = sortList(p->next); //右鏈表 p->next = NULL; //將其斷開,為兩個鏈表 ListNode *right = sortList(head); return merge(left, right); } ListNode *merge(ListNode *left, ListNode *right) { ListNode dummy(0); //申請一個假節點 ListNode *p = &dummy; while (left&&right){ if (left->val < right->val){ p->next = left; left = left->next; } else{ p->next = right; right = right->next; } p = p->next; } if (left)p->next = left; if (right)p->next = right; return dummy.next; } };