一尘不染

JavaScript数组的大O

algorithm

JavaScript中的数组非常容易通过添加和删除项来进行修改。它在某种程度上掩盖了一个事实,即大多数语言数组都是固定大小的,并且需要复杂的操作来调整大小。似乎JavaScript可以轻松编写性能不佳的数组代码。这导致了一个问题:

对于数组性能,我可以从JavaScript实现中获得什么样的性能(就O时间的复杂性而言)?

我假设所有合理的JavaScript实现最多都具有以下大O。

  • 存取权-O(1)
  • 追加-O(n)
  • 前置-O(n)
  • 插入-O(n)
  • 删除-O(n)
  • 交换-O(1)

JavaScript使您可以使用new Array(length)语法将数组预填充为特定大小。(奖金问题:是以O(1)或O(n)的方式创建数组)这更像是常规数组,并且如果用作预大小数组,则可以允许O(1)追加。如果添加了循环缓冲区逻辑,则可以实现O(1)前置。如果使用动态扩展数组,则O(log
n)将是这两种情况的平均情况。

我可以期望某些事情比我的假设有更好的性能吗?我不希望任何规范概述任何内容,但实际上,可能是所有主要实现都在幕后使用了优化的数组。是否在工作中动态扩展数组或其他一些提高性能的算法?

聚苯乙烯

我想知道这是因为我正在研究一些排序算法,当描述它们的整体大O时,大多数似乎都假定追加和删除是O(1)运算。


阅读 224

收藏
2020-07-28

共1个答案

一尘不染

注意:虽然这个答案在2012年是正确的,但当今引擎对对象和数组使用的内部表示形式都非常不同。这个答案可能是正确的,也可能不是。

与大多数使用Java数组实现数组的语言相反,数组是对象,值存储在哈希表中,就像常规对象值一样。因此:

  • 存取权-O(1)
  • 追加-摊销O(1)(有时需要调整哈希表的大小;通常仅需要插入)
  • 通过前置-O(n)unshift,因为它需要重新分配所有索引
  • 插入-如果值不存在,则摊销O(1)。如果要转移现有值(例如,使用splice),则为O(n )。
  • 删除-分摊O(1)以删除值O(n)(如果要通过分配索引)splice
  • 交换-O(1)

通常,设置或取消设置dict中的任何键都是摊销O(1),对于数组,无论索引是什么,也是如此。需要重新编号现有值的任何操作都是O(n),这仅仅是因为您必须更新所有受影响的值。

2020-07-28