Array 函数的 JavaScript 运行时复杂性
ECMA 规范没有指定边界复杂度,但是,您可以从规范的算法中推导出一个。
push
是O(1),但是,实际上它会在引擎定义的边界遇到O(N)复制成本,因为需要重新分配槽数组。这些边界通常是对数的。
pop
是O(1)与类似的警告push
但O(N)副本很少遇到,因为它经常被折叠到垃圾收集中(例如,复制收集器只能复制数组的已使用部分)。
shift
最坏的情况是O(N),但在特殊情况下,它可以实现为O(1),代价是降低索引速度,因此您的里程可能会有所不同。
slice
是O(N),其中N是end - start
。如果没有显着减慢对两个阵列的写入速度,这里的优化机会并不多。
splice
是,最坏的情况,O(N)。有一些数组存储技术将N除以一个常数,但它们会显着减慢索引速度。如果引擎使用此类技术,您可能会注意到操作异常缓慢,因为它在访问模式更改触发的存储技术之间切换。
你没有提到的一个是sort
。在平均情况下,它是O(N log N)。但是,根据引擎选择的算法,在某些情况下您可能会得到O(N^2)。例如,如果引擎使用 QuickSort(即使延迟到 InsertionSort),它也有众所周知的N^2 种情况。这可能是您的应用程序的 DoS 来源。如果这是一个问题,请限制您排序的数组的大小(可能合并子数组)或救助到 HeapSort。
顺便提一下,可以使用 RingBuffer (iow CircularQueue / CircularBuffer) 数据结构在 O(1) 中实现shift
/ unshift
, push
/pop
方法。当循环缓冲区不需要增长时,最坏的情况是 O(1)。有没有人实际测量过这些操作的性能?知道总是比猜测更好......
slice 仅在所取数字未知时才为线性。如果切片数是常数,则切片是常数,不是线性的。