该算法属于mergesort,我知道您可能觉得很奇怪,但我的主要重点是计算该算法的空间复杂度。
如果我们查看mergesort函数的递归树并尝试跟踪算法,则堆栈大小将为log(n)
。但是由于merge
中也有mergesort
函数,该函数正在创建两个大小为n/2
,n/2
的数组,因此我首先应该找到递归关系的空间复杂度,然后再确定,我应该添加将成为n/2 + n/2
的{{1}}。
我知道答案,但是我对此过程感到困惑。谁能告诉我正确的程序吗?
这种混淆是由于合并函数不是递归的,而是在递归函数中调用的
为什么我们说空间复杂度将为O(log(n) + n)
并通过递归函数空间复杂度的定义,我们通常计算递归树的高度
O(log(n) + n)
答案 0 :(得分:2)
MergeSort时间复杂度是O(nlgn),这是基础知识。合并排序空间的复杂度将始终为O(n)(包括数组在内)。如果您绘制出空间树,则似乎空间复杂度为O(nlgn)。但是,由于该代码是“深度优先”代码,因此您始终只会沿树的一个分支进行扩展,因此,所需的总空间使用将始终由O(3n)= O(n)限制。
例如,如果您绘制出空间树,则好像是O(nlgn)
16 | 16
/ \
/ \
/ \
/ \
8 8 | 16
/ \ / \
/ \ / \
4 4 4 4 | 16
/ \ / \ / \ / \
2 2 2 2..................... | 16
/ \ /\ ........................
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | 16
其中树的高度为O(logn)=>空间复杂度为O(nlogn + n)= O(nlogn)。但是,在实际代码中情况并非如此,因为它不是并行执行的。例如,在N = 16的情况下,这就是mergesort的代码执行的方式。 N = 16。
16
/
8
/
4
/
2
/ \
1 1
注意使用的空间数是32 = 2n = 2 * 16 <3n
然后它向上合并
16
/
8
/
4
/ \
2 2
/ \
1 1
,即34 <3n。然后它向上合并
16
/
8
/ \
4 4
/
2
/ \
1 1
36 <16 * 3 = 48
然后向上合并
16
/ \
8 8
/ \
4 4
/ \
2 2
/\
1 1
16 + 16 + 14 = 46 <3 * n = 48
在较大的情况下,n = 64
64
/ \
32 32
/ \
16 16
/ \
8 8
/ \
4 4
/ \
2 2
/\
1 1
是64 * 3 <= 3 * n = 3 * 64
对于一般情况,您可以通过归纳证明。
因此,即使您使用数组实现,只要合并后清理使用的空间并且不并行但顺序执行代码,空间复杂度始终由O(3n)= O(n)限制。
我的实现示例如下:
答案 1 :(得分:1)
此MergeSort
的实现在内存空间上效率很低,并且存在一些错误:
Array
未被Merge
传递给MergeSort
。 Array
为每个递归级别分配了MergeSort
大小的额外空间,因此至少是初始数组大小的两倍( 2 * N 如果垃圾收集是最佳的(例如,如果它使用引用计数),则是必需的;如果垃圾收集器是惰性的,则最多使用 N * log2(N)空间。这远远超出了要求,因为精心实施可能只占用 N / 2 个额外空间。