【问题标题】:Why ArrayList add() and add(int index, E) complexity is amortized constant time? Why not O(1) for add(), O(n) for add(int index, E)? [duplicate]为什么 ArrayList add() 和 add(int index, E) 复杂度是摊销常数时间?为什么 add() 不是 O(1),add(int index, E) 不是 O(n)? [复制]
【发布时间】:2017-12-26 12:23:59
【问题描述】:

为什么 ArrayList add() 和 add(int index, E) 复杂度是摊销常数时间?

为什么不是 O(1) 用于单个 add() 操作,O(n) 用于单个 add(int index, E) 操作和 O(n) 用于使用 (any) add 添加 n 个元素(n 个添加操作)方法?假设我们很少使用 add(int index, E) 添加到数组末尾?

数组(和ArrayList)不是已经有n个元素的一种操作复杂度:

  1. add() - O(1)?
  2. add(int index, E) - O(n)?

如果我们进行一百万次插入,1 和 2 的平均值不可能是 O(1),对吧?

为什么甲骨文说

加法运算以摊销常数时间运行,即加n 元素需要 O(n) 时间

我认为 add() 的复杂度为 O(1),add(int index, E) 的复杂度为 O(n)。

这是否意味着“n个操作的积分复杂度”(每个操作的复杂度为O(1))可以说是n * O(1)= O(n)。我错过了什么?

也许对于 Oracle 来说“添加操作”总是只意味着 add()?而 add(int, E) 是“插入操作”?然后就彻底明白了!

我有一个猜测,它与渐近分析摊销分析之间的差异有关,但我无法掌握到最后。

What is amortized analysis of algorithms?

Why the time complexity of an array insertion is O(n) and not O(n+1)?

More appropriate to say Amortized O(1) vs O(n) for insertion into unsorted dynamic array?(不太清楚)

Big O when adding together different routines

【问题讨论】:

  • Isn't inserting with add(int index, E) 99% 的时间不在数组末尾,这意味着它还会触发至少一些最右边元素的移动,并且对于足够大的数组(已经有插入了许多元素)这样的移动总是O(n)?不管容量/调整大小问题?意思是 add(int index, E) (几乎)总是 O(n)?那么为什么要摊销 O(1)?
  • 谁说add(int, E) 不是 O(n)?
  • 但是 Oracle 在 ArraList 文档中的意思是:“添加操作在摊销的常数时间内运行”???他们的意思是只有 add()?让我们猜猜它们是什么意思?可能他们将 add(int, E) 称为“插入”,而不是添加...
  • 是的,那只是指add(E)
  • 源代码告诉你你需要知道的一切

标签: java arrays arraylist time-complexity


【解决方案1】:

用 Oracle 术语(默示)和谈论 List

  • 添加方法”(同义词 - “追加方法”)总是表示boolean add(E)
  • 插入方法”总是表示boolean add(int index, E)

Oracle 写入时

加法运算以摊销常数时间运行,即加 n 元素需要 O(n) 时间。

意思是:

单个boolean add(E) 操作的复杂性摊销为 O(1)。

它不能只是 O(1) 渐近(总是),因为我们很少需要增加数组容量。这个添加操作实际上是“创建新的更大的数组,将旧数组复制到其中,然后在末尾添加一个元素”操作是 O(n) 渐近复杂度,因为在增加 List 容量时复制数组是 O( n),增长加加的复杂度为 O(n) [计算为 O(n) + O(1) = O(n)]。如果没有这种容量增长操作,增加的复杂性将是 O(1),元素总是被添加(附加)到数组的末尾(最大索引)。如果我们“添加”(= 插入)而不是数组末尾,我们将需要移动最右边的元素(具有更大的索引),并且单个此类操作的复杂度将是 O(n)。

现在,对于单个加法运算,渐近复杂度对于不增加容量的加法是 O(1),对于加法容量增加的情况是 O(n)(这种情况非常罕见)。

单个加法运算的摊销复杂度为 O(1)。它反映了这样一个事实,即罕见的 O(n) 增长和加法操作会被更多的 O(1) 加法运算“稀释”,因此“平均而言”单个操作是 O(1)。

n 次加法运算的“渐近复杂度”为 O(n)。但是这里我们谈论的是 n 个操作的复杂性,而不是一个操作的复杂性。这不是一种严格的说法(“渐近复杂性”),但无论如何。 n 次操作的摊销复杂度就更没有意义了。

最后,boolean add(int index, E) 单个操作的复杂度总是 O(n)。如果触发grows,则为O(n) + O(n) [grow + insert],但2*O(n)与O(n)相同。

【讨论】:

    猜你喜欢
    • 2013-03-21
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 2015-11-30
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多