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

CHAN_傑發表於2020-09-07

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

8c47e58b6247676f3ef14e617a4686bc258cc573e36fcf67c1b0712fa7ed1699-Picture2

利用歸併排序,我們可以將時間複雜度降至O(nlogn), 並且我們是對連結串列進行排序,可以通過修改引用來更改節點順序,無需像陣列一樣開闢而外的空間。

利用遞迴實現連結串列的歸併排序有兩個環節:

分割cut環節:

我們可以利用fast, slow快慢雙指標實現連結串列的分割, fast一次移動兩位, slow一次移動一位,當fast移動到末尾時,slow移動到中間位置。

利用變數為tmp = slow.next記錄後連結串列的頭節點,並將slow.next = null將前後連結串列斷開。

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環節:

使用輔助指標,將前後連結串列後合併為一個有序連結串列

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;
  //...
}

明白上面的兩個環節後,就能輕鬆明白我們完整的演算法了。

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;
    }

相關文章