Algorithm 在最坏的情况下,合并排序的空间复杂度如何为O(n)?
O(n)复杂度意味着最坏情况下的合并排序占用的内存空间等于初始数组中存在的元素数。但是在进行递归调用时,它不是创建了新的数组吗?这个空间怎么不算 注意:正如在评论中向我指出的,这个答案是错误的。我把它放在这里,因为我相信它对大多数想了解这些事情的人都有帮助,但请记住,这个算法实际上被称为就地mergesort,并且可以具有与纯mergesort不同的运行时复杂性 合并排序很容易实现,可以对所有内容使用相同的数组,而无需创建新数组。只需在每个递归调用中发送边界。这样的话(在伪代码中):Algorithm 在最坏的情况下,合并排序的空间复杂度如何为O(n)?,algorithm,sorting,complexity-theory,mergesort,space-complexity,Algorithm,Sorting,Complexity Theory,Mergesort,Space Complexity,O(n)复杂度意味着最坏情况下的合并排序占用的内存空间等于初始数组中存在的元素数。但是在进行递归调用时,它不是创建了新的数组吗?这个空间怎么不算 注意:正如在评论中向我指出的,这个答案是错误的。我把它放在这里,因为我相信它对大多数想了解这些事情的人都有帮助,但请记住,这个算法实际上被称为就地mergesort,并且可以具有与纯mergesort不同的运行时复杂性 合并排序很容易实现,可以对所有内容使用相同的数组,而无需创建新数组。只需在每个递归调用中发送边界。这样的话(在伪代码中): Merge
MergeSort有足够的内存,只有一个与原始数组大小相同的缓冲区 在通常的版本中,执行从阵列到额外缓冲区的合并,然后复制回阵列
在高级版本中,可以执行从数组到额外缓冲区的合并,反之亦然。如果自顶向下合并排序的最坏情况实现在对自身进行递归调用之前在mergesort()中分配数组的两部分,则它可能比原始数组占用更多的空间 更高效的自顶向下合并排序使用一个entry函数,该函数一次性分配临时缓冲区,将临时缓冲区的地址作为参数传递给一对相互递归的函数中的一个,这些函数生成索引并在两个数组之间合并数据 在自底向上合并排序的情况下,可以使用1/2原始数组大小的临时数组,合并数组的两半,最后是临时数组中的前一半数据,然后是原始数组中的后一半数据,最后再合并回原始数组
然而,在这两种情况下,空间复杂度都是O(n),因为大O忽略了2或1/2之类的常数。在合并排序中,空间复杂度总是ω(n),因为您必须将元素存储在某个地方。在使用数组的实现中,额外的空间复杂度可以是O(n),在链表实现中,额外的空间复杂度可以是O(1)。在实践中,使用列表的实现需要为列表指针提供额外的空间,因此除非您已经在内存中拥有了列表,否则这并不重要。编辑如果你计算堆栈帧,那么它是O(n)+O(logn),所以在数组的情况下仍然是O(n)。在列表的情况下,它是O(logn)额外的内存
这就是为什么在合并排序复杂性分析中,人们会提到“额外的空间需求”之类的东西。很明显,您必须将元素存储在某个地方,但最好提及“附加内存”以阻止纯粹主义者。为什么您认为它不会创建新的数组?它需要为每个合并步骤将元素复制到新数组请参见此,您是指创建新数组时的内存开销吗?即使5n+999也是O(n)。您所描述的是就地合并排序,不容易实现。你确实是对的。我错了!我将把它作为一个例子,说明不彻底地思考某件事会导致错误的结论。
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