在典型的动态数组实现中,当没有新元素的空间时,我们将堆栈加倍。在这种情况下,推动操作的平均时间加倍是O(n)。
推送的复杂性是什么,如果不是加倍,我们将堆栈大小增加了(n + k)?
我的方法如下
假设堆栈为空,并且k = 10,我们将堆栈增加到10个元素。在10个元素之后,我们将其设为20个元素,依此类推。
复制元素的平均时间是10 + 20 + 30 + ...
因此推送的平均时间必须是O(n)的顺序?
我的方法是否正确?
答案 0 :(得分:4)
您的计算不正确。动态数组的典型实现将其大小加倍(或者更常见的是,通过 x 百分比增加其大小)是有原因的。
如果你将大小从1增加到n = 2 i ,你复制的元素总量是1 + 2 + 4 + 8 + 16 + ... + 2 我。如果对此求和,则它小于2 i + 1 ,因此总时间复杂度为O(n),并且一次插入的amortized time complexity为O(1)。如果n不是2的幂,则计算会稍微复杂一些,但结果将是相同的。
另一方面,如果你将大小增加k,从0增加到n = i * k,你复制的元素总量是k + 2k + 3k + ... + ik。如果对此求和,则为(ik + k)*(ik / k)/ 2 = O(n 2 )。并且一次插入的摊销复杂性将是O(n)。
正因为如此,你的解决方案要比加倍大小更糟糕。
答案 1 :(得分:1)
根据您增加存储量的方式而且k足够小,对于所有情况或其他情况,它可能是O(1)。
通过'how',我的意思是,在托管语言中,人们会创建一个大小为n + k的新数组,然后将旧数组(大小为n)复制到新数组,最后替换旧数组的引用新的。那将是:O(1)(数组创建,它是一个假设)+ O(n)(数据复制)+ O(1)(参考变化)。我们忽略垃圾收集器执行,因为它非常依赖于实现。在非托管语言中,可以使用类似于realloc
的内容,以便保留旧元素而无需复制,因为新存储占用相同的内存区域,仅扩展到所需项目的数量。在这种情况下,对于所有情况都是O(1)。请注意,然而,由于内存碎片,有时将存储扩展到所需项目的数量是不可能的,因此采用类似于托管语言的方法(但是由realloc
实现隐式完成)。对于这个,复杂性与托管语言相同:O(n)。
从实际的角度来看,这是答案,我希望你能从上述答案的分析角度找到答案。祝你好运。