JS标准在Array
,push
,pop
,shift
或slice
等常见splice
函数上定义的运行时复杂性? ESP。我有兴趣在随机位置删除和插入条目。如果没有定义复杂性,我可以期待什么,例如在V8?
(这个问题的灵感来自于this。此外,this benchmark,张贴here,也让我很好奇,但也许这是一些无关的现象。)
(一个非常相关的问题是here。然而,关于接受的答案的评论之一说现在是错的。而且,接受的答案没有任何参考标准真正定义它的方式)。
答案 0 :(得分:64)
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。
答案 1 :(得分:2)
答案 2 :(得分:0)
仅需注意,可以使用RingBuffer(iow CircularQueue / CircularBuffer)在O(1)中实现const flipPairs = str => str.replace(/(.)(.)/g, '$2$1');
console.log(flipPairs("hello world"));
/ shift
,unshift
/ push
方法数据结构。每当不需要循环缓冲区增长时,最坏的情况就是O(1)。有人实际衡量过这些操作的绩效吗?总是比不猜测更容易知道...
答案 3 :(得分:-3)
切片只是线性的。如果切片编号是常数,则切片是常量,而不是线性。