<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Sort List ### Source - leetcode: [Sort List | LeetCode OJ](https://leetcode.com/problems/sort-list/) - lintcode: [(98) Sort List](http://www.lintcode.com/en/problem/sort-list/) ~~~ Sort a linked list in O(n log n) time using constant space complexity. ~~~ ### 題解1 - 歸并排序(鏈表長度求中間節點) 鏈表的排序操作,對于常用的排序算法,能達到 O(nlogn)O(n \log n)O(nlogn)的復雜度有快速排序(平均情況),歸并排序,堆排序。快速排序不一定能保證其時間復雜度一定滿足要求,歸并排序和堆排序都能滿足復雜度的要求。在數組排序中,歸并排序通常需要使用 O(n)O(n)O(n) 的額外空間,也有原地歸并的實現,代碼寫起來略微麻煩一點。但是對于鏈表這種非隨機訪問數據結構,所謂的「排序」不過是指針`next`值的變化而已,主要通過指針操作,故僅需要常數級別的額外空間,滿足題意。堆排序通常需要構建二叉樹,在這道題中不太適合。 既然確定使用歸并排序,我們就來思考歸并排序實現的幾個要素。 1. 按長度等分鏈表,歸并雖然不嚴格要求等分,但是等分能保證線性對數的時間復雜度。由于鏈表不能隨機訪問,故可以先對鏈表進行遍歷求得其長度。 1. 合并鏈表,細節已在 [Merge Two Sorted Lists | Data Structure and Algorithm](http://algorithm.yuanbin.me/zh-cn/linked_list/merge_two_sorted_lists.html) 中詳述。 在按長度等分鏈表時進行「后序歸并」——先求得左半部分鏈表的表頭,再求得右半部分鏈表的表頭,最后進行歸并操作。 由于遞歸等分鏈表的操作需要傳入鏈表長度信息,故需要另建一輔助函數。新鮮出爐的源碼如下。 ~~~ /** * Definition of ListNode * class ListNode { * public: * int val; * ListNode *next; * ListNode(int val) { * this->val = val; * this->next = NULL; * } * } */ class Solution { public: /** * @param head: The first node of linked list. * @return: You should return the head of the sorted linked list, using constant space complexity. */ ListNode *sortList(ListNode *head) { if (NULL == head) { return NULL; } // get the length of List int len = 0; ListNode *node = head; while (NULL != node) { node = node->next; ++len; } return sortListHelper(head, len); } private: ListNode *sortListHelper(ListNode *head, const int length) { if ((NULL == head) || (0 >= length)) { return head; } ListNode *midNode = head; int count = 1; while (count < length / 2) { midNode = midNode->next; ++count; } ListNode *rList = sortListHelper(midNode->next, length - length / 2); midNode->next = NULL; ListNode *lList = sortListHelper(head, length / 2); return mergeList(lList, rList); } ListNode *mergeList(ListNode *l1, ListNode *l2) { ListNode *dummy = new ListNode(0); ListNode *lastNode = dummy; while ((NULL != l1) && (NULL != l2)) { if (l1->val < l2->val) { lastNode->next = l1; l1 = l1->next; } else { lastNode->next = l2; l2 = l2->next; } lastNode = lastNode->next; } lastNode->next = (NULL != l1) ? l1 : l2; return dummy->next; } }; ~~~ ### 源碼分析 1. 歸并子程序沒啥好說的了,見 [Merge Two Sorted Lists | Data Structure and Algorithm](http://algorithm.yuanbin.me/zh-cn/linked_list/merge_two_sorted_lists.html). 1. 在遞歸處理鏈表長度時,分析方法和 [Convert Sorted List to Binary Search Tree | Data Structure and Algorithm](http://algorithm.yuanbin.me/zh-cn/binary_search_tree/convert_sorted_list_to_binary_search_tree.html) 一致,**`count`表示遍歷到鏈表中間時表頭指針需要移動的節點數。**在紙上分析幾個簡單例子后即可確定,由于這個題需要的是「左右」而不是二叉搜索樹那道題需要三分——「左中右」,故將`count`初始化為1更為方便,左半部分鏈表長度為`length / 2`, 這兩個值的確定最好是先用紙筆分析再視情況取初值,不可死記硬背。 1. 找到中間節點后首先將其作為右半部分鏈表處理,然后將其`next`值置為`NULL`, 否則歸并子程序無法正確求解。這里需要注意的是`midNode`是左半部分的最后一個節點,`midNode->next`才是鏈表右半部分的起始節點。 1. 遞歸模型中**左、右、合并**三者的順序可以根據分治思想確定,即先找出左右鏈表,最后進行歸并(因為歸并排序的前提是兩個子鏈表各自有序)。 ### 復雜度分析 遍歷求得鏈表長度,時間復雜度為 O(n)O(n)O(n), 「折半取中」過程中總共有 log(n)\log(n)log(n) 層,每層找中點需遍歷 n/2n/2n/2 個節點,故總的時間復雜度為 n/2?O(logn) n/2 \cdot O(\log n)n/2?O(logn) (折半取中), 每一層歸并排序的時間復雜度介于 O(n/2)O(n/2)O(n/2) 和 O(n)O(n)O(n)之間,故總的時間復雜度為 O(nlogn)O(n \log n)O(nlogn), 空間復雜度為常數級別,滿足題意。 ### 題解2 - 歸并排序(快慢指針求中間節點) 除了遍歷鏈表求得總長外,還可使用看起來較為巧妙的技巧如「快慢指針」,快指針每次走兩步,慢指針每次走一步,最后慢指針所指的節點即為中間節點。使用這種特技的關鍵之處在于如何正確確定快慢指針的起始位置。 ### C++ ~~~ /** * Definition of ListNode * class ListNode { * public: * int val; * ListNode *next; * ListNode(int val) { * this->val = val; * this->next = NULL; * } * } */ class Solution { public: /** * @param head: The first node of linked list. * @return: You should return the head of the sorted linked list, using constant space complexity. */ ListNode *sortList(ListNode *head) { if (NULL == head || NULL == head->next) { return head; } ListNode *midNode = findMiddle(head); ListNode *rList = sortList(midNode->next); midNode->next = NULL; ListNode *lList = sortList(head); return mergeList(lList, rList); } private: ListNode *findMiddle(ListNode *head) { if (NULL == head || NULL == head->next) { return head; } ListNode *slow = head, *fast = head->next; while(NULL != fast && NULL != fast->next) { fast = fast->next->next; slow = slow->next; } return slow; } ListNode *mergeList(ListNode *l1, ListNode *l2) { ListNode *dummy = new ListNode(0); ListNode *lastNode = dummy; while ((NULL != l1) && (NULL != l2)) { if (l1->val < l2->val) { lastNode->next = l1; l1 = l1->next; } else { lastNode->next = l2; l2 = l2->next; } lastNode = lastNode->next; } lastNode->next = (NULL != l1) ? l1 : l2; return dummy->next; } }; ~~~ ### 源碼分析 1. 異常處理不僅考慮了`head`, 還考慮了`head->next`, 可減少輔助程序中的異常處理。 1. 使用快慢指針求中間節點時,將`fast`初始化為`head->next`可有效避免無法分割兩個節點如`1->2->null`[fast_slow_pointer](#)。 - 求中點的子程序也可不做異常處理,但前提是主程序`sortList`中對`head->next`做了檢測。 1. 最后進行`merge`歸并排序。 ****> 在遞歸和迭代程序中,需要尤其注意終止條件的確定,以及循環語句中變量的自增,以防出現死循環或訪問空指針。 ### 復雜度分析 同上。 ### Reference - [Sort List | 九章算法](http://www.jiuzhang.com/solutions/sort-list/) - fast_slow_pointer > . [LeetCode: Sort List 解題報告 - Yu's Garden - 博客園](http://www.cnblogs.com/yuzhangcmu/p/4131885.html)[ ?](# "Jump back to footnote [fast_slow_pointer] in the text.")
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看