【问题标题】:How to Merge sort a Linked List with O(nlogn) time and O(1) space complexity如何对具有 O(nlogn) 时间和 O(1) 空间复杂度的链表进行合并排序
【发布时间】:2017-04-22 15:01:01
【问题描述】:

(免责声明:学校)

据我所知,递归拆分链表,然后将其发送到另一个函数进行合并是 O(nlogn) 时间和 O(n) 空间。是否可以在 O(nlogn) 时间和 O(1) 空间复杂度的链表上进行归并排序?你会怎么做呢?

任何帮助表示赞赏

PS:要确保传统的归并排序是空间复杂度0(n),这是0(n)的一个例子吧?对于 O(1) 空间,它将如何改变?

void sortTrack() { 
    Node merge = this.head;
    this.head = Node (merge);
}

public Node mergeSort(Node head){
    if ((head == null)||(head.next == null)){
        return head;
    }
    Node left = head;
    Node right = head.next;
    while((right != null) && right.next != null){
        head = head.next;
        right = right.next.next;
    }
    right = head.next;
    head.next = null;
    return merge(mergeSort(left), mergeSort(right));
}

public Node merge(Node left, Node right){
    Node head = new Node ();
    Node temp = head;
    while((left != null) && (right !=null)){
        if(left <= right ){
            temp.next = left;
            temp = left;
            left = left.next;
        }
        else{
            temp.next = right;
            temp = right; 
            right = right.next;
        }
    }
    if(right == null)
        temp.next = left;
    else
        temp.next = right;
    return head.next;
}  

【问题讨论】:

    标签: java linked-list mergesort


    【解决方案1】:

    您的递归方法需要 Θ(log n) 额外空间,因为当您一路走来时,您将在堆栈上进行 Θ(log n) 调用归结为对单例列表进行合并排序。

    要将其减少到 O(1) 额外空间,您需要改变递归“自上而下”的方法,将列表拆分为两个大的子列表,对它们进行排序,然后合并结果 - 为您提供Θ(log n) 的递归 depth — 到迭代的“自下而上”方法,您首先对所有单例列表排序,然后对所有对(第一个和第二个元素,然后是第三个和第四个等),然后是所有的四重奏(第一个到第四个元素,然后是第五个到第八个等)——给你 Θ(log n) 通过列表。每次通过需要 Θ(n) 时间,所以总时间仍然是 Θ(n log n)。

    总的来说,您将拥有三种方法:

    • Node merge(Node listA, Node listB),你已经写好了。

    • Node mergePass(Node list, int i):

      • 前提:节点#1到#n排序,节点#(n+1)到#(2n)排序等。
      • 后置条件:节点 #1 到 #(2n) 已排序,节点 #(2n+1) 到 #(4n) 进行排序,等等。
      • 通过抓取节点 #1 到 #n 和节点 #(n+1) 到 #(2n) 来工作,“切割" 他们出来,打电话给merge,然后把结果“粘贴”进去;然后对节点 #(2n+1) 到 #(3n) 和节点 #(3n+1) 到#(4n);等
    • Node mergeSort(Node list):

      • 对其参数调用mergePass(..., 1)
      • 在结果上调用mergePass(..., 2),然后在那个结果上调用mergePass(..., 4),等等,每次都加倍i
      • i 是列表长度(或更大)之前停止,因为如果i 这么大,mergePass(..., i) 是空操作。
      • 返回最后一个结果。

    【讨论】:

    • 感谢您的分解。你介意给我一个例子或伪代码之类的吗?我不知道如何实施自下而上的方法
    • @RobBor:我已经为你添加了更多细节。
    • @RobBor - wiki 有一个 bottom up merge sort for linked list 的示例,它使用一个小的(25 到 32)固定大小的指针数组或对内部工作列表节点的引用,这将被认为是恒定的空间复杂度 O (1).
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 2019-07-10
    • 1970-01-01
    • 2020-12-13
    相关资源
    最近更新 更多