1. 程式人生 > >單鏈表的歸併排序

單鏈表的歸併排序

Question: 148. Sort List

Sort a linked list in O(n log n) time using constant space complexity.
中文:使用恆定的空間複雜度排序一個連結串列,要求時間複雜度是O(nlogn)

我們知道題目的要求是時間複雜度是O(nlogn), 很自然我們就想到了二路歸併排序或則是快速排序。碎玉快速排序來說,設計到大量的精準索引定位,所以對於雙鏈表來說更加適合,而這裡是單鏈表,所以我選擇二路歸併排序。

現在我們這裡需要用單鏈表實現,唯一的區別就是連結串列的分片,這裡的分片我們選用的方法是雙指標法,每次一個指標後移一位,另外一個後移兩位。

/**
 * 合併兩個有序連結串列
 * @param l1
 * @param l2
 * @return
 */
private static ListNode merge(ListNode l1, ListNode l2) {
    ListNode l = new ListNode(0), p = l;

    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            p.next = l1;
            l1 = l1.next;
        } else {
            p.next = l2;
            l2 = l2.next;
        }
        p = p.next;
    }

    if (l1 != null)
        p.next = l1;

    if (l2 != null)
        p.next = l2;

    return l.next;
}

/**
 * 連結串列的二路歸併排序
 * @param head
 * @return
 */
public static ListNode sortList(ListNode head) {
    //空連結串列或則只有一個結點,直接返回head
    if(head == null || head.next==null){
        return head;
    }

    //1. 將list 切分為兩個部分
    ListNode prev=null, slow=head, fast=head;

    while (fast !=null && fast.next !=null){
        prev = slow;
        slow = slow.next;//slow指標後移一個數據
        fast = fast.next.next;//fast指標後移兩個資料
    }

    prev.next = null;//將連結串列切斷

    //分別排序前後兩個部分
    ListNode l1 = sortList(head);
    ListNode l2 = sortList(slow);

    return merge(l1, l2);
}

測試用例:

public static void main(String[] args) {
    ListNode head = new ListNode(0);
    ListNode n1 = new ListNode(2);
    ListNode n2 = new ListNode(4);
    ListNode n3 = new ListNode(1);
    ListNode n4 = new ListNode(3);
    head.next = n1;
    n1.next = n2;
    n2.next=n3;
    n3.next =n4;

    ListNode h =  sortList(head);

    while (h!=null){
        System.out.print(h.val + ",");
        h = h.next;
    }
}

執行結果:

0,1,2,3,4,