如何仅使用O(1)空间在链接列表上实现MergeSort?

时间:2017-04-23 07:52:56

标签: java linked-list mergesort space-complexity

怎么会这样做呢?自下而上的mergesort方式是否满足O(1)额外空间要求?传统的mergesort是什么让它不是O(1)空间?

这会是一种方式吗?

void mergeSort() { 
    ListNode merge = this.head;
    this.head = mergeSort(merge);
}

ListNode mergeSort(ListNode head) {
    if(head == null || head.next == null)
        return head;

    ListNode slow = head; ListNode fast = head.next; 
    while(fast!=null && fast.next !=null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    ListNode left = head; ListNode right = slow.next;
    slow.next = null;
    left = mergeSort(left);
    right = mergeSort(right);
    return merge(left, right);
}

ListNode merge(ListNode L, ListNode R) {
    if(L==null) return R;
    if(R==null) return L;
    ListNode h = null;
    if(L.val <= R.val )){
        h = L;
        h.next = merge(L.next, R);
    } else {
        h = R;
        h.next = merge(L, R.next);
    }
    return h;
}

1 个答案:

答案 0 :(得分:2)

链接列表的自顶向下合并排序将消耗O(log(n))堆栈空间,并且由于扫描列表以分割它们,因此它比自下而上方法慢。由于递归merge(),问题中的示例代码将占用O(n)堆栈空间。

链表的自下而上合并排序使用一个小的(25到32)固定大小的节点引用(或指针)数组,这将满足O(1)空间要求。链接到wiki文章。如果感兴趣,我可以发布示例java代码。

https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists

示例java代码:

    // merge two already sorted lists
    public ListNode merge(ListNode list0, ListNode list1) {
        if(list0 == null)
            return list1;
        if(list1 == null)
            return list0;
        ListNode temp = new ListNode(0);   // dummy node
        ListNode dest = temp;
        while(true){
            if(list0.element <= list1.element){
                dest.next = list0;
                dest = list0;
                list0 = list0.next;
                if(list0 == null){
                    dest.next = list1;
                    break;
                }
            } else {
                dest.next = list1;
                dest = list1;
                list1 = list1.next;
                if(list1 == null){
                    dest.next = list0;
                    break;
                }
            }
        }
        return temp.next;
    }
    // sort list
    public ListNode sort(ListNode head) {
        final int NUMLIST = 32;
        ListNode[] alist = new ListNode[NUMLIST];
        ListNode node;
        ListNode next;
        int i;
        // if < 2 nodes, return
        if(head == null || head.next == null)
            return;
        node = head;
        // merge node into array
        while(node != null){
            next = node.next;
            node.next = null;
            for(i = 0; (i < NUMLIST) && (alist[i] != null); i++){
                node = merge(alist[i], node);
                alist[i] = null;
            }
            if(i == NUMLIST)   // don't go past end of array
                i--;
            alist[i] = node;
            node = next;
        }
        // node == null
        // merge array into single list
        for(i = 0; i < NUMLIST; i++)
            node = merge(alist[i], node);
        return node;
    }