可调整大小的数组和分期运行时间

时间:2016-12-15 01:59:19

标签: c++ arrays algorithm

"因此,插入N个元素需要总计O(N)。每次插入平均为O(1),尽管某些插入在最坏的情况下需要O(N)时间。"这句话可以在Cracking the Coding Interview中找到。我有点理解这句话,尽管有一点关于它的事情让我感到厌烦。在好日子,摊销的插入是O(1)。这只是意味着当可调整大小的数组不需要调整大小时,插入一些东西就是O(1)。这很清楚。但是,在糟糕的一天,当我们用完空间时,我们需要O(N)来插入额外的元素。但是,我不同意上面的陈述,当它说某些插入在最坏的情况下采取O(N)。不应该说,在最坏的情况下,一次插入需要O(N)。

为了说明这一点,以下是我所说的一个例子。

假设我们有一个可调整大小的数组,但我们的数组大小为4.我们现在说插入5个元素,我们将有O(1),O(1),O(1),O( 1),但是一旦我们到达最后一个元素,我们将不得不将所有这些人复制到一个新的数组中,这个过程会给我们一个O(N)的成本。

有人可以帮我澄清一下。我不明白为什么当我们在旧阵列中运行空间时,只需要将所有元素复制到新数组中时,本书会说某些情况需要O(N)。

4 个答案:

答案 0 :(得分:1)

我认为你最好像这样理解上述陈述。

起初。数组大小只是1.并插入一个元素。现在数组已经满了!你必须把它的大小调整为前一次的2倍。

接下来,数组大小为2.让此过程进行。您可以很容易地注意到,必须调整数组大小的时刻是1,2,4,8,16,32,...,2 ^ r。

我会给你问题。

  1. 您需要调整阵列大小的次数是多少?
  2. 直到N(N> = 0)的总成本是多少?
  3. 第一个答案是楼层(lgN)次。我想你可以轻松搞清楚。如果你找到第一个答案,计算这N个步骤的总成本是第二个答案很容易。(我不知道如何表达数学符号:<)

    1 + 2 + 4 + 8 + 16 + ... + 2 ^(floor(lgN))= 2 ^(floor(lgN)+1) - 1 =>为O(n)

    要获得每个步骤的平均成本,请将总成本除以N => O(1)

    我认为参考文献提到的最坏情况是需要调整数组的大小。这种重新调整的成本与数组中元素的数量成比例,O(N)

答案 1 :(得分:1)

以可调整大小的数组内N次插入的代价为例(我将在此处使用代字号):

  • N次插入的成本=新元素插入的成本+调整大小的成本

插入新元素的费用

这只是在数组中插入新元素的成本乘以插入新元素(即N :)的次数乘以

  • 新元素插入的费用= 1 * N

调整大小的费用

想象一下,您有一个64个单元的阵列。然后,这意味着该数组的大小已调整为:

  • 数组大小= 1-> 2-> 4-> 8-> 16-> 32-> 64
  • #resize完成= 6

已将64个单元阵列的大小调整了6倍,即,调整大小发生了log2(64)次。 通常,现在我们知道对于N插入,我们将执行log2(N)调整大小操作。

但是,每次调整大小后我们要做什么?我们将在新的调整大小的数组中复制数组中已经存在的元素:在调整大小“ i”时,我们将复制多少个元素? 2 ^ i。对于前面的示例:

  • 调整数字1 = 1-> 2:复制1个元素
  • 调整数字2 = 2-> 4:复制2个元素
  • 调整数字3 = 4-> 8:复制4个元素
  • ......
  • 调整数字6 = 32-> 64:复制32个元素

所以:

  • 调整大小的成本=汇总(从i = 1到log2(N))2 ^ i = 2(N-1)

结论

  • N次插入的成本 =新元素插入的成本+调整大小的成本= N + 2(N-1)〜 3N

答案 2 :(得分:0)

std::vector会将所有元素保持在内存中以便快速迭代 - 这是它的事情,它的作用是什么,这就是为什么每个人都喜欢{{1} 1}}。通常它会保留比其中包含的元素数量所需的空间更多的空间,或者内存恰好是免费的,所以当你在std::vector的末尾添加一个新元素时,它会很快让vector将你的新元素推到那里。

然而,当vector没有空间展开时,它不能将现有元素留在原处并在其他地方开始新列表 - 所有元素必须紧挨着彼此在记忆中!所以它必须找到一大块内存,对于所有元素和新元素都足够大,然后将所有现有元素复制到那里,然后将新元素添加到最后。

如果添加1个元素需要1个单位时间,从广义上讲,N个元素需要N个单位。如果添加新元素,那就是一个操作。如果添加新元素,则需要重新定位1024个现有元素,即1025次操作。因此,重新分配所需的时间与向量的大小成正比,因此vector

答案 3 :(得分:0)

让我们将所有插入分成“重”插入,这些插入需要时间与元素数量和“光”插入成比例,这些插入只需要花费一定的时间来完成。然后,如果你从一个空列表开始并继续附加一个附加,你将会有大部分轻量插入,但是你时不时会有大量的插入。

让我们说,为简单起见,每次空间用完时你都要加倍数组的大小,然后用大小为4的数组开始。然后第一个调整大小将需要移动四个元素,第二个将移动八,然后十六,然后是三十二,然后六十四,然后是128,然后是256,等等。

请注意,它不仅仅是一个需要花费很长时间的单个追加 - 粗略地说,如果你有n次插入,那么它们的大致log n将很重(它们之间的时间不断增长)而另一个大概是n - 他们的日志会很轻。