O(n)复杂度意味着合并排序在最坏的情况下占用的内存空间等于初始数组中存在的元素数量。但是,在进行递归调用时,它还没有创建新数组吗?如何计算这个空间?
答案 0 :(得分:2)
自顶向下合并排序的最坏情况实现可能比原始数组占用更多空间,如果它在对自身进行递归调用之前在mergesort()中分配数组的两半。
更高效的自顶向下合并排序使用一个入口函数,该函数对临时缓冲区进行一次性分配,将临时缓冲区的地址作为参数传递给生成索引的一对相互递归函数之一合并两个数组之间的数据。
在自下而上合并排序的情况下,可以使用原始数组大小1/2的临时数组,合并数组的两半,最后得到临时数组中前半部分的数据,以及原始数组的后半部分,然后进行最终合并回原始数组。
然而,在任何一种情况下,空间复杂度都是O(n),因为大O会忽略像2或1/2这样的常数。
答案 1 :(得分:1)
MergeSort足够使用与原始数组大小相同的单个缓冲区。
在通常的版本中,您执行从数组到额外缓冲区的合并并复制回数组。
在高级版本中,您执行从数组到额外缓冲区的合并,相反,交替执行。
答案 2 :(得分:0)
注意:这个答案是错误的,正如评论中指出的那样。我把它留在这里,因为我认为它对大多数想要理解这些东西的人有帮助,但请记住,这个算法实际上被称为就地mergesort ,并且可能具有与纯归并排序
合并排序很容易实现,无需创建新数组即可为所有内容使用相同的数组。只需在每次递归调用中发送边界即可。所以像这样(伪代码):
mergesort(array) ->
mergesort'(array, 0, length of array - 1)
mergesort'(array, start, end) ->
mergesort'(array, start, end/2)
mergesort'(array, end/2+1, end)
merge(array, start, end/2, end/2+1, end)
merge(array, start1, end1, start2, end2) ->
// This function merges the two partitions
// by just moving elements inside array
答案 3 :(得分:-1)
在Merge Sort中,空间复杂度始终为omega(n),因为您必须将元素存储在某处。在使用数组和链表实现中的O(1)的实现中,额外的空间复杂度可以是O(n)。在实践中,使用列表的实现需要额外的空间用于列表指针,所以除非你已经在内存中有列表,否则它无关紧要。编辑堆栈帧,然后它是O(n)+ O(log n),所以在数组的情况下仍然是O(n)。如果是列表,则为O(log n)附加内存。
这就是为什么在合并排序复杂性分析中人们会提到'额外的空间需求'或类似的东西。很明显,你必须将元素存储在某个地方,但最好提一下“额外的记忆”来保持纯粹主义者的存在。