Mergesort的这个合并函数是取O(1)space还是O(n)space?

Does this merge function of Mergesort take O (1) space or O(n) space?

private ListNode merge(ListNode list1, ListNode list2) {
    ListNode dummy = new ListNode(0);
    ListNode curr = dummy;
    while (list1 != null && list2 != null) {
        if (list1.val < list2.val) {
            curr.next = list1;
            list1 = list1.next;
        } else {
            curr.next = list2;
            list2 = list2.next;
        }
        curr = curr.next;
    }
    if (list1 == null) {
        curr.next = list2;
    } else {
        curr.next = list1;
    }
    return dummy.next;
}

这里我相信由于“curr”节点,它需要 O(n) space,因为 curr 节点将逐渐包含完整的链表。

merge 函数使用 O(1) space。除了具有恒定大小的局部变量外,它只在 ListNode dummy = new ListNode(0);

中分配一个 ListNode

函数的其余部分只是更改 list1list2.

指向的列表元素的 next 成员

可以通过将初始测试写入 select 结果列表的初始节点来修改函数,甚至不分配一个额外的对象。

将此函数与自上而下的递归方法或自下而上的迭代方法相结合会产生具有 O(log(N)) space 复杂度和O(N.log(N)) 时间复杂度。

要实现稳定排序,比较运算符应该改为<=

这里是没有任何分配的修改版本:

private ListNode merge(ListNode list1, ListNode list2) {
    Listnode head, curr;
    if (list1 == null)
        return list2;
    if (list2 == null)
        return list1;
    if (list1.val <= list2.val) {
        curr = head = list1;
        list1 = list1.next;
    } else {
        curr = head = list2;
        list2 = list2.next;
    }
    while (list1 != null && list2 != null) {
        if (list1.val <= list2.val) {
            curr = curr.next = list1;
            list1 = list1.next;
        } else {
            curr = curr.next = list2;
            list2 = list2.next;
        }
    }
    curr.next = (list1 != null) ? list1 : list2;
    return head;
}

这是一个在大多数情况下测试较少的修改版本:

private ListNode merge(ListNode list1, ListNode list2) {
    Listnode head, curr;
    if (list1 == null)
        return list2;
    if (list2 == null)
        return list1;
    if (list1.val <= list2.val) {
        curr = head = list1;
        list1 = list1.next;
        if (list1 == null) {
            curr.next = list2;
            return head;
        }
    } else {
        curr = head = list2;
        list2 = list2.next;
        if (list2 == null) {
            curr.next = list1;
            return head;
        }
    }
    for (;;) {
        if (list1.val <= list2.val) {
            curr = curr.next = list1;
            list1 = list1.next;
            if (list1 == null) {
                curr.next = list2;
                return head;
            }
        } else {
            curr = curr.next = list2;
            list2 = list2.next;
            if (list2 == null) {
                curr.next = list1;
                return head;
            }
        }
    }
}

在C或C++中,可以更改原始代码以避免使用指针分配:

static ListNode *merge(ListNode *list1, ListNode *list2) {
    ListNode *head = NULL;
    ListNode **nextp = &head;
    while (list1 && list2) {
        if (list1->val <= list2->val) {
            *nextp = list1;
            nextp = &list1->next;
            list1 = list1->next;
        } else {
            *nextp = list2;
            nextp = &list2->next;
            list2 = list2->next;
        }
    }
    *nextp = list1 ? list1 : list2;
    return head;
}