Leetcode:148_Sort List | O(nlogn)鏈表排序 | Medium


題目:Sort List

Sort a linked list in O(n log n) time using constant space complexity

看題目有兩個要求:1)時間復雜度為O(nlogn);2)空間復雜度為常數,即不能增設額外的空間。
滿足這樣要求的排序算法,我們首先想到快排,合並排序和堆排序。我們來分析下幾種排序算法對時間和空間復雜度的要求,堆排序實現上過於繁瑣,我們不做考慮。快排的最壞的時間復雜度是O(n^2),平均復雜度為O(nlgn),如果按照題目的嚴格要求顯然快排是不滿足的,而且快排的實現引入了遞歸操作,遞歸調用的棧空間嚴格意義上說也是額外空間。另外值得注意的一點是:鏈表不像數組一樣,可以隨機訪問元素,鏈表必須順序訪問,所以一般的遞歸操作很難實現,雖然也可以實現哈,見該文:遞歸實現鏈表排序。對於歸並排序,我們知道需要O(n)的空間復雜度,即需要一個臨時數組來存放排好序的元素,顯然也合理,但那是針對的是數組,對於鏈表,歸並排序的空間復雜度為in-place sort,即不需要額外空間就可以完成。另外,歸並排序還有一個比較好的優勢是其穩定性。所以,對於本題的解法,我們首選歸並排序。

歸並排序有多種方式,總的來說有三種,1)遞歸;2)非遞歸;3)自然合並;詳見本文:歸並排序的三種實現方法。對於鏈表,采用非遞歸的方式更為高效,用以下的一幅圖來說明非遞歸的方式:

將兩兩子列表進行合並組合,達到排序的目的。本題的代碼如下,參考上文實現的。

 1 ListNode *sortList(ListNode *head) 
 2 {
 3     assert(NULL != head);
 4     if (NULL == head)
 5         return NULL;
 6 
 7     ListNode *p = head;
 8     int len = 0;        //get the length of link
 9     while (NULL != p) {
10         p = p->next;
11         len ++;
12     }
13 
14     ListNode *temp = new ListNode(0);
15     temp->next = head;
16     
17     int interval = 1;   //合並子列表的長度
18     for (; interval <= len; interval *= 2) {
19         ListNode *pre = temp;
20         ListNode *first = temp->next;  //兩段子列表的起始位置
21         ListNode *second = temp->next;
22 
23         while (NULL != first || NULL != second) {
24             int i = 0;
25             while (i < interval && NULL != second) {
26                 second = second->next; //將second移到第二段子列表的起始處
27                 i ++;
28             }
29 
30             int fvisit = 0, svisit = 0; //訪問子列表的的次數<interval,保證列表中的元素全部能被訪問
31             while (fvisit < interval && svisit < interval && NULL != first && NULL != second) {
32                 if (first->val < second->val) {
33                     pre->next = first;
34                     pre = first;
35                     first = first->next;
36                     fvisit ++;
37                 }
38                 else {
39                     pre->next = second;
40                     pre = second;
41                     second = second->next;
42                     svisit ++;
43                 }
44             }
45             while (fvisit < interval && NULL != first) {
46                 pre->next = first;
47                 pre = first;
48                 first = first->next;
49                 fvisit ++;
50             }
51             while (svisit < interval && NULL != second) {
52                 pre->next = second;
53                 pre = second;
54                 second = second->next;
55                 svisit ++;
56             }
57             pre->next = second;
58             first = second;
59         }
60     }
61     ListNode *retResult = temp->next;
62     delete temp;
63     temp = NULL;
64     return retResult;
65 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM