合并排序的空间要求

时间:2010-06-03 15:00:57

标签: algorithm sorting mergesort

我正在尝试了解Mergesort的空间要求,O(n) 我看到时间要求基本上是,等级(logn)* merge(n)的数量因此使得(n log n)。
现在,我们仍然在每个级别分配n个,左右两个不同的阵列 我明白这里的关键是,当递归函数返回时,空格会被释放,但我没有看到它太明显。
此外,我找到的所有信息,只是说明所需的空间是O(n),但不解释它 任何提示?

function merge_sort(m)
    if length(m) ≤ 1
        return m
    var list left, right, result
    var integer middle = length(m) / 2
    for each x in m up to middle
         add x to left
    for each x in m after middle
         add x to right
    left = merge_sort(left)
    right = merge_sort(right)
    result = merge(left, right)
    return result

修改 好的,多亏了@Uri,这就是诀窍 我一开始没看到的是时间只是添加,而内存增加和减少,所以最大时间是在执行结束时,但最大内存量在递归堆栈的底部。

所以,如果我们继续添加n + n / 2 + n / 4 + n / 8 ....我们添加多少次并不重要,它永远不会大于2n,当我们到达时递归堆栈底部并开始上升,我们不保留用于前一个分支的内存,因此在max,2n将是使用的内存量O(n)。

2 个答案:

答案 0 :(得分:14)

有一些版本的合并排序可以在适当的位置使用。

但是,在大多数实现中,空间是数组大小的线性。这意味着第一级为n,第二级为n / 2,第三级为n / 4,等等。当你处于递归的底部时,这个系列加起来约为2n,这是线性的。

答案 1 :(得分:0)

这是我对代码空间复杂性的解释。基本上,当算法达到结果时,我们如何在内存上做。

1)你所做的每个递归调用都有一个恒定大小的堆栈帧,以及任何不是“n”函数的变量。 我们称这个常量为“c”。因为,你将深入lg(n)级别,结果是c * lg(n),即O(lg(n))。

2)现在,当我们计算结果时,我们为n /(2 ^ k)个元素分配空间,其中k是你所处的水平。

left = merge_sort(left)
right = merge_sort(right)

对于那些可能想知道我们如何提出n /(2 ^ k)的人,请注意首先我们在解决数组的前半部分时分配内存,即left = merge_sort(left)。一旦这个递归树结束,我们最终解除所有内存的释放,并在解决右侧之前回到起点。因此,它的n /(2 ^ k)。 这将是O(n)。

3)最后,合并程序也可以分配额外的空间(如果使用链接列表可能不需要这个空间),这是O(n)

最终答案= O(lg(n))+ O(n)+ O(n),即O(n)。