(免责声明:上学)
据我所知,递归拆分链表,然后将其发送到另一个要合并的函数是O(nlogn)时间和O(n)空间.是否可以在链表上进行合并,具有O(nlogn)时间和O(1)空间复杂度?你会怎么做呢?
任何帮助都表示赞赏
PS:为了确保传统的mergesort是空间复杂度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;
}
最佳答案 您的递归方法需要Θ(log n)额外空间,因为当您一直向下合并排序单例列表时,您将在堆栈上进行Θ(log n)调用.
要将其减少到O(1)额外空间,您需要从递归的“自上而下”方法进行更改,将列表拆分为两个大的子列表,对它们进行排序,并合并结果 – 为您提供递归深度Θ(log n) – 迭代的“自下而上”方法,你首先对所有单例列表进行排序,然后对所有对(第一和第二元素,然后是第三和第四,等等)进行排序,然后全部四重奏(第一到第四个元素,然后第五到第八个等) – 给你Θ(log n)通过列表.每次传递需要Θ(n)时间,因此总时间仍为Θ(n log n).
总的来说,你将有三种方法:
>节点合并(节点列表A,节点列表B),您已经编写过.
>节点mergePass(节点列表,int i):
>前提条件:节点#1到#n被排序,节点#(n 1)到#(2n)被排序等.
>后置条件:节点#1到#(2n)被排序,节点#(2n 1)到#(4n)被排序等.
>通过抓取节点#1到#n和节点#(n 1)到#(2n),“切断”它们,调用merge,并“粘贴”结果来工作;然后对节点#(2n 1)到#(3n)和节点#(3n 1)到#(4n)做同样的事情;等等
>节点mergeSort(节点列表):
>在其参数上调用mergePass(…,1).
>在结果上调用mergePass(…,2),然后在该结果上调用mergePass(…,4)等,每次加倍.
>在我是列表的长度(或更大)之前停止,因为如果我是那么大,mergePass(…,i)是无操作.
>返回最后一个结果.