1. 程式人生 > >利用遞迴實現連結串列的排序(歸併排序)

利用遞迴實現連結串列的排序(歸併排序)

### 利用遞迴實現連結串列的排序(歸併排序) ![8c47e58b6247676f3ef14e617a4686bc258cc573e36fcf67c1b0712fa7ed1699-Picture2](https://tva1.sinaimg.cn/large/007S8ZIlgy1giien8ulgwj30z70qb41v.jpg) 利用歸併排序,我們可以將時間複雜度降至*O(nlogn)*, 並且我們是對連結串列進行排序,可以通過修改引用來更改節點順序,無需像陣列一樣開闢而外的空間。 利用遞迴實現連結串列的歸併排序有兩個環節: **分割cut環節:** 我們可以利用`fast, slow`快慢雙指標實現連結串列的分割, `fast`一次移動兩位, `slow`一次移動一位,當`fast`移動到末尾時,`slow`移動到中間位置。 利用變數為`tmp = slow.next`記錄後連結串列的頭節點,並將`slow.next = null`將前後連結串列斷開。 ```java ListNode sortList(ListNode head) { if (head == null || head.next == null) return head; ListNode fast = head.next, slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; // 一次移動兩位 slow = slow.next; // 一次移動一位 } ListNode tmp = slow.next; // 記錄後連結串列的頭節點 slow.next = null; // 將前後連結串列斷開 //... } ``` **cut遞迴的終止條件** base case 為當`head.next == null`,即連結串列只有一個節點。 **歸併merge環節:** 使用輔助指標,將前後連結串列後合併為一個有序連結串列 ![](https://img2020.cnblogs.com/blog/2134418/202009/2134418-20200907212633907-31291078.gif) ```java ListNode sortList(ListNode head) { //... // left 為前連結串列的頭節點, right 為後連結串列的頭節點, h 為輔助節點 while (left != null && right != null) { if (left.val < right.val) { h.next = left; left = left.next; } else { h.next = right; right = right.next; } h = h.next; } h.next = left != null ? left : right; //... } ``` 明白上面的兩個環節後,就能輕鬆明白我們完整的演算法了。 ```java ListNode sortList(ListNode head) { if (head == null || head.next ==null) return head; // cut過程 ListNode fast = head.next, slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } ListNode tmp = slow.next; slow.next = null; // merage過程 ListNode left = sortList(head); ListNode right = sortList(tmp); ListNode h = new ListNode(0); ListNode res = h; while (left != null && right != null) { if (left.val < right.val) { h.next = left; left = left.next; } else { h.next = right; right = right.next; } h = h.next; } h.next = left != null ? left : right; return res.next;