在自上而下的合并排序中,以这种方式调用递归函数:
void mergesort(Item a[], int l, int r) {
if (r <= l) return;
int m = (r+l)/2;
mergesort(a, l, m);
mergesort(a, m+1, r);
merge(a, l, m, r);
}
在教科书中给出了该策略的空间复杂度为O(n)。而如果我们仔细观察递归:我们在递归调用中将指针传递给数组。其次,通过将底部节点合并到父节点,以遍历的顺序解析递归。所以每次堆栈上都有O(logn)变量(或堆栈上的O(log n)帧)。那么,尽管采用了就地合并技术,空间复杂性如何才是O(n)呢?
答案 0 :(得分:4)
那么,如果采用就地合并技术,空间复杂度如何才是O(n)呢?
因为您书中给出的实现可能不使用就地合并技术。如果需要O(1)空间和O(n log n)时间排序,则通常首选heapsort来合并排序,因为它更容易。只有当你谈论排序列表时,做O(1)合并排序才有意义......然后,这很容易做到。为例如指定的合并排序链表是O(1)空格和O(n log n)时间。
这里的根本误解似乎是:时间复杂性适用于算法,而不是它们解决的问题。我可以写一个O(n ^ 3)合并排序,如果我想...并不意味着我的算法不是O(n ^ 3),它没有说明你的O(n log n)合并分类。这与计算复杂性略有不同,我们在这里讨论例如在P中出现问题...如果存在多项式时间算法,则问题出在P中。然而,P中的问题也可以通过非多项式时间算法来解决,如果你考虑一下,构造这样的算法是微不足道的。同样适用于空间复杂性。
答案 1 :(得分:2)
你是正确的,递归调用占用的空间是O(log n)。
但是数组本身占用的空间是O(n)。
总空间复杂度为O(n)+ O(log n)。
这是O(n),因为它的上限是(n)=&gt; 2(n)。
答案 2 :(得分:1)
您如何在n
空间中存储log n
个项目?这没有意义。如果您要对n
项进行排序,O(n)
空间是您最好的。
答案 3 :(得分:0)
由于除了常量之外没有在mergesort函数内部分配任何空间,因此该空间复杂度为O(lg(n))。但是你的合并程序会在数组的情况下分配内存,因此保持它的意思是它变成O(lg(n))+ O(n)= O(n)。如果使用链表,则可以避免合并过程中的临时空间,从而达到O(lg(n)最佳。